home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops ƒ / Class < prev    next >
Text File  |  1998-06-15  |  77KB  |  2,862 lines

  1. ¥ High-level class/object implementation.
  2.  
  3. cr .( loading Class...)
  4.  
  5.  
  6. ¥ : >classxt            >classCfa  ;
  7. ¥ : aligned_addr?        cfa?  ;
  8.  
  9.  
  10. (*
  11. Note that the object header format is documented at "object building"
  12.  below.
  13.  
  14. Jan 96    mrh/imk    Added various mods to object initialization contributed
  15.                 by Ivo Krab.
  16.                 
  17. Jul 96    mrh        Mods made to support large_obj_array
  18.         mrh/rh    Incorporated bug fix from Reinout Heeck, so multiple
  19.                  records in unions work.
  20. Sep 96    mrh        Better inline{ - eliminating explicit out-of-line code
  21.                 8-way hashing of methods
  22.  
  23. ==============================================================================
  24.  
  25. Here are all our various class/object formats:
  26.  
  27.  
  28.  
  29.             ================= Object header ======================
  30.  
  31. Note if the obj is an ivar, it doesn't have a header if it's in a record,
  32. unless the ivar is indexed.  Indexed ivars always have headers, no matter
  33. what, since the indexing code relies on it.
  34.  
  35.  
  36. 2 bytes        Offset to the indexed area, rel to the class pointer
  37.             (which follows).  If not indexed, this will be 6.
  38.  
  39. 4 bytes        Class pointer (relocatable).
  40.  
  41. 2 bytes        Offset from the data start to the class pointer.
  42.             For simple objects (i.e. not embedded), this is -6.
  43.             For embedded objects, it will be more negative.  Note it
  44.             will always be negative.
  45.  
  46. (object's data starts here)
  47.  
  48. For indexed objects, the indexed area (after the ivars) is preceded by
  49. the indexed descriptor (xdesc) with this format:
  50.  
  51. 2 bytes        Width of indexed elements (in bytes)
  52. 4 bytes        Number of elements minus 1 (i.e. LIMIT-1).
  53.             The low word of this is used by a CHK instruction
  54.             if #elements is < 32K.
  55.  
  56. If indexing is attempted on a non-indexed object, the "offset to the
  57. indexed area" will be 6, taking us to the beginning of the object's
  58. data.  The CHK instruction will be done at offset -2 from there, which
  59. won't be the #elements, of course, but will be the offset to the
  60. class pointer WHICH IS ALWAYS NEGATIVE!!  Thus the CHK will always fail!
  61. This was a deliberate trick - about the only place in Mops I've
  62. resorted to anything like this, you'll be glad to know.  (At least I've
  63. described it for you!)
  64.  
  65. This trick has very limited usefulness now, since all the indexed
  66. methods are now defined in INDEXED-OBJ rather than OBJECT, so normally
  67. an indexed method on a non-indexed class wouldn't be found.  However
  68. the check comes for free, so I've retained it.
  69.  
  70.  
  71.         ==============  Class dictionary entry  ================
  72.  
  73. link/name/hndlr    as for normal colon definitions
  74. 4 bytes            call to BLD - the word which builds an object
  75. 32 bytes        links to 8-way hashed method chains (relative)
  76. 4 bytes            link to ivar chain (relative)
  77. 2 bytes            non-indexed data length
  78. 2 bytes            width of indexed elements, or zero if not indexed
  79. 2 bytes            flags
  80. 2 bytes            "xdispl offs" - the ivar offset where indexing starts
  81.                  (used by large_obj_arrays), or zero if none.
  82. 4(n+1) bytes    n-way to superclasses (n relocatable addrs terminated by zero)
  83.  
  84. Flag bits:
  85.     $0001        "large" - indexed with > 64K elements.
  86.     $0002        class is exported from a module
  87.  
  88.  
  89.         ==============  ivar dictionary entry  ================
  90.  
  91. 4 bytes        hashed name
  92. 4 bytes        link to prev ivar dic entry (relative addr)
  93. 4 bytes        class pointer (relocatable)
  94. 2 bytes        offset of this ivar's data from the base addr of the class
  95. 2 bytes        number of elements if indexed, or zero if not
  96. 2 bytes        flags
  97.  
  98. Flag bits: (zero is rightmost - what will we do on PowerPC?)
  99.  
  100. bit 0        1 = ivar gets an object header
  101. bit 1        1 = this is a static ivar
  102. bit 2        1 = this is a public ivar
  103.  
  104. Note: although indexed objects can have 2^^32 elements, we are
  105. assuming that an ivar can't have more than 64K elements.  This is
  106. because we are limiting the maximum ivar length of a class to 64K bytes,
  107. which is a stricter condition.  Would anybody want a longer ivar than
  108. this??
  109.  
  110.         ==============  Method dictionary entry  ================
  111.  
  112. 4 bytes        hashed name
  113. 4 bytes        link to prev method dic entry (relative addr)
  114. 2 bytes        flags
  115.  
  116.     (method code follows - this is the method's cfa here)
  117.  
  118. Flag bits:
  119.  
  120. bit 0        1 = private method (note other way round to ivars - we're using
  121.                 1 for the unusual case)
  122. bit 7        1 = there's a callFirst and/or callLast method
  123.  
  124.  
  125.         ==========================================================
  126. *)
  127.  
  128.  
  129. : xx  db ;            ¥ useful!
  130.  
  131.     26    constant    static_ivar_offs
  132.                             ¥ the offset from the start of the ivar dic
  133.                             ¥  info for a static ivar, to the ivar's data.
  134.                             ¥  The ivar info is 18 bytes long, then the
  135.                             ¥  ivar is instantiated immediately, with the
  136.                             ¥  usual 8-byte object header.  Total: 26.
  137.  
  138.     0    value    PUB/PRIV    ¥ -1 private, 1 public, 0 default - for ivars and methods
  139. false    value    STATIC?        ¥ true if following ivars are to be static
  140.     0    value    ^COMP_CLASS    ¥ addr of the class we're currently compiling
  141.     0    value    PIVAR        ¥ hashed name of any public ivar we're accessing
  142.     0    value    PIVSEL        ¥ hashed selector of any msg being sent to
  143.                             ¥  to a public ivar
  144.  
  145.     0    value    NEWOBJECT    ¥ addr of object being created
  146.     0    value    #SUP        ¥ number of superclasses for current class
  147.     0    value    SUPERS_TO_SKIP
  148.     0    value    INITID
  149.  
  150.  
  151. variable METAADDR            ¥ will hold relocatable address of pseudoclass
  152.                             ¥  Meta. Used in NW_IVSETUP to find if end
  153.                             ¥  of superclass chain has been reached
  154.  
  155.  
  156. ¥                ===============================
  157. ¥                        UTILITY WORDS
  158. ¥                ===============================
  159.  
  160. : PRIVATE        -1 -> pub/priv  ;        ¥ following methods and ivars will be private
  161. : PUBLIC         1 -> pub/priv  ;        ¥ following methods and ivars will be public
  162.  
  163. : END_PRIVATE    0 -> pub/priv  ;        ¥ back to the default
  164. : END_PUBLIC    0 -> pub/priv  ;        ¥ ditto
  165.  
  166.  
  167. : X    bld  123  ;                ¥ The 123 blocks optimization!
  168.  
  169. ' x @  forget x      constant    CLASSMK        ¥  JSR  bldVec-base(A3)
  170.  
  171. : EXBASE    $ 4E92  w,  ;    immediate    ¥  JSR  (A2)
  172.  
  173. : >OBJ  ( cfa -- ^obj )  inline{ 8 +}  ;
  174. : OBJ>  ( ^obj -- cfa )  inline{ 8 -}  ;
  175.             ¥ Note: we don't use >class here, since obj> shouldn't be
  176.             ¥ used for embedded objects, and it is used during obj
  177.             ¥ building when the ^class isn't there yet.
  178.  
  179. : CHKCLASS    ¥ ( cfa -- cfa )
  180.     class?  ?EXIT
  181.     .id  space  true ?error 80  ;
  182.  
  183. : ?>CLASS   ( ^obj -- ^class )
  184.     >class  dup 0= ?error 81  ;        ¥ If no legal class ptr, probably
  185.                                     ¥ not an obj addr at all!
  186.  
  187. ¥ the following offsets refer to where a ^class points, i.e. the cfa
  188. ¥ of the class.
  189.  
  190. (*    MFA_offset picks one of the 8 method threads, given a selID.
  191.     The selID is probably not very random in the low byte (since
  192.     selectors all end in ":", so we hash it a little more then pick
  193.     the 3 bits from the result which are already in the right position.
  194.  
  195.     Note: it took a surprising amount of trial and error to get a
  196.     good extra hash for this particular use!
  197. *)
  198.  
  199. : MFA_offset  ( selID ^class -- selID ^class MFA_offset )
  200.     over
  201.     dup 5 >> +
  202.     $ 1C and  4+  ;
  203.  
  204. : MFA  ( SelID ^Class -- SelID MFA )  MFA_offset  + ;
  205.  
  206. 36    constant    IFA_offset
  207.  
  208. : IFA    inline{ IFA_offset +} ;    ¥ ivar link
  209. : DFA    inline{ 40 +}    ;        ¥ Data len (2 bytes),
  210.                                  ¥  width of indexed elts (2 bytes)
  211. : FFA    inline{ 44 +}    ;        ¥ Flags (2 bytes)
  212. : XOFFA    inline{ 46 +}    ;        ¥ indexing offset for large_obj_arrays (2 bytes)
  213. : SFA    inline{ 48 +}    ;        ¥ Superclass N-way starts here
  214.  
  215. 48    constant    classSize        ¥ total size of class info up to N-way
  216.  
  217.  
  218. ¥ : GETDLEN        ¥ ( ^obj -- n )  Gets length of object's named ivars
  219. ¥    ?>class dfa w@  ;
  220.  
  221. : (^DLEN)    ¥ ( ^obj -- ^datalen )  This is a low-level word which should
  222.             ¥  normally only be used in the Mops system stuff.  Note it
  223.             ¥  takes ^obj, not ^class, and it doesn't do a module check
  224.             ¥  - it assumes the class is in the same segment as the object.
  225.     ?>class dfa  ;
  226.  
  227.  
  228. : (DLEN&XWID)    ( ^class -- dlen xwid )    ¥ Assumes ^class is the true class
  229.         dfa dup  w@  swap  2+ w@  ;        ¥  addres, not main dictionary address
  230.                                         ¥  of exported class in module
  231.                                         ¥ Only intended for internal use!
  232.  
  233. : DLEN&XWID        ( ^class -- dlen xwid )
  234.         ?>classInMod
  235.         (dlen&xwid)
  236.         ?unHoldMod  ;
  237.  
  238.  
  239. : DLEN    dlen&xwid  drop  ;
  240. : XWID    dlen&xwid  nip   ;
  241.  
  242. : IVARLEN    postpone dlen  ;    immediate        ¥ an alias for dlen
  243.  
  244. : OBJLEN    ¥ ( -- objlen )  Computes total data length of current object.
  245.  
  246.     ^base (^dlen)  dup w@  swap 2+ w@  ?dup
  247.     IF  idxBase 4- @ 1+  *  + 4+  THEN   ;
  248.  
  249.  
  250. : ?>MAINDIC  { ^class -- '^class }
  251.         ¥ If ^class is exported from a module, we return the main dic
  252.         ¥ equivalent.  If it's not exported, we return it unchanged.
  253.         ¥ We need this word since for exported classes, we need to use the
  254.         ¥ imported address (in the main dictionary) as the class pointer
  255.         ¥ in a new object or an ivar dic entry (so that the module will be
  256.         ¥ invoked properly when a method is sent to the object.
  257.  
  258.     ^class ffa 1+ 1 btest
  259.     IF        ^class >name n>count sfind drop
  260.     ELSE    ^class
  261.     THEN  ;
  262.  
  263.  
  264. : LARGE_OBJ_ARRAY_CHECK  { ^class offs ¥ xoffs  -- offs xdispl-offs }
  265.  
  266. ¥ Following <findm> or <IVfindm>, we check if this is a large_obj_array,
  267. ¥  in which case we might have to map the obj/ivar into the indexed area:
  268.  
  269.     ^class xoffa w@  -> xoffs    ¥ offs where remapping ends - are we before that?
  270.     ^class searchedClass <>
  271.     offs xoffs <  and
  272.     IF            ¥ yes - remapping necessary.  Return offs to xdispl ivar
  273.         offs  xoffs 12 +
  274.     ELSE        ¥ no - normal case - just return zero
  275.         offs 0
  276.     THEN
  277. ;
  278.  
  279.  
  280. : <findM>  { selID ^class ¥ cfa offs  -- cfa offs xdispl-offs }
  281.  
  282. (*    Factored out from clFndm and objFindm.  Finds a method's cfa given a
  283.     selID and a class address, which has already been converted to a module
  284.     addr if necessary.
  285.     
  286.     offs will be nonzero if the method turns out to belong to a superclass
  287.     with a non-zero offset in the object - i.e. an embedded object.
  288.     If it's a large_obj_array, and the object is in the indexed area,
  289.     xdispl-offs will be nonzero.  This allows the caller to compile
  290.     code to add the offset to the selected element.
  291. *)
  292.  
  293.     ^class -> objClass                    ¥ used in error msgs and inline binding
  294.  
  295.     selID ^class MFA_offset true  (findm)
  296.     NIF  cr  ^class .id  108 die        ¥ "method not found"
  297.     THEN
  298.     -> cfa  -> offs
  299.     offs -> emb_obj_offs                ¥ may need this in inline binding
  300.     cfa
  301.     ^class offs  large_obj_array_check
  302. ;
  303.  
  304.  
  305. : <findIV>  { selID ^class ¥ ^ivar offs xoffs -- ^ivar offs xdispl-offs T | -- F  }
  306.  
  307. (*    Basic routine to look for an ivar.  It's not an error if we don't find it,
  308.     so we return a flag.
  309. *)
  310.     selID ^class IFA_offset false (findm)  NIF  false  EXIT  THEN
  311.     8 -  -> ^ivar  -> offs        ¥ note - (findm) has returned the base
  312.                                 ¥  offs here.
  313.     ^ivar 12 + w@  ++> offs
  314.     ^ivar
  315.     ^class offs  large_obj_array_check
  316.     true
  317. ;
  318.  
  319.  
  320. : ClFindM  { selID ^class ¥ cfa offs xoffs -- cfa offs xdispl-offs }
  321.                                                 
  322. (*    finds a method's cfa given a selID and a class address, which hasn't
  323.     been checked for being in a module.  The returned results are as
  324.     described above for <findM>.
  325. *)
  326.     ^class ?>classInMod -> ^class
  327.     selID ^class  <findM>
  328. ;
  329.  
  330.  
  331. : ObjFindM  { selID ^obj ¥ ^class cfa offs xoffs  -- cfa offs xdispl-offs
  332.                                                 | -- cfa offs 0 }
  333.  
  334. (* Finds a method's xt given a selID and an obj addr.  The returned
  335.     results are as described above for <findM>.
  336. *)
  337.     ^obj >class  -> ^class
  338.     ^class NIF  81 die  THEN            ¥ "not an object"
  339.     selID ^class  <findM>
  340. ;
  341.  
  342.  
  343. : IVFindM    ¥ ( selID ^ivar -- xt offs xdispl-offs )
  344. ¥  Looks for a method in an ivar.
  345.  
  346.     8 + @abs        ¥ addr of ivar's class
  347.     clFindm  ;
  348.  
  349.  
  350. : SEND  { ^obj selID ¥ svMB -- }    ¥  Executes a method given its sel ID.  Used
  351.                                     ¥      in late binding.  Can also be used if you
  352.                                     ¥   have a dynamically determined method ID.
  353.     modBase -> svMB
  354.     selID ^obj  objFindM
  355.     ?dup
  356.     IF        ^obj + dup @ + +
  357.     ELSE    ^obj +
  358.     THEN
  359.     swap  ex-method
  360.     svMB -> modBase  ;
  361.  
  362.  
  363. : (DEFER)  ( ^obj -- )        ¥ Looks up SelID at IP and runs the method.
  364.                             ¥  Used in late binding.
  365.     @(ip)  send  ;
  366.  
  367.  
  368. 0 -> quitvec   0 -> abortvec   0 -> objInit        ¥ clear vectors
  369. ' pfind  -> ufind
  370.  
  371.  
  372. : ?CLASS        ¥ Error if not compiling a class definition.
  373.     cstate 0=  ?error 115  ;
  374.  
  375.  
  376.  
  377. (*    IVFIND is called when we've parsed a selector.  It determines if the next
  378.     word is an ivar.
  379.     Note: if found, <findIV> returns the equivalent of the cfa of
  380.     a method, which for ivars, is the addr of the class pointer.
  381. *)
  382.  
  383. : ivFind  { str-addr ¥ xdispl-offs -- ^ivar offs xdispl-offs T |  -- str-addr F }
  384.     str-addr
  385.     cstate  NIF  false  EXIT  THEN
  386.     hash ^comp_class  <findIV>        ¥ ( ^ivar offs xdispl-offs  T  |  F )
  387.     IF        true
  388.     ELSE    DP  false
  389.     THEN
  390. ;
  391.  
  392.  
  393. ¥ TOfind looks for a temp (local) object.
  394.  
  395. : TOfind  { str-addr -- ^ivar offs T | -- str-addr F  }
  396.     str-addr
  397.     tmpObjs  NIF  false  EXIT  THEN
  398.     hash
  399.     tmpObjs <findIV>
  400.     IF                    ¥ ( -- ^ivar offs xdispl-offs )
  401.             drop        ¥ xdispl-offs must be zero for class Dummy
  402.             dup $ FFFE >=
  403.             IF            ¥ self or super - mustn't match these in class Dummy!
  404.                 2drop  str-addr false  EXIT
  405.             THEN
  406.             true
  407.     ELSE    str-addr false
  408.     THEN
  409. ;
  410.     
  411. (*
  412. LocFind will be called from Ufind, which is the vector that gets first
  413. shot at recognizing a word.
  414. It looks at all the possibilities involving local names, which are
  415. not in the regular dictionary.  These possibilities are: named parms/locals,
  416. local objects, and if a class is being compiled, ivars of this class.
  417.  
  418. In the latter case, we arrange for the ivar's address to
  419. be pushed at run time simply by compiling ^base followed by an add of the
  420. ivar's offset - our code generation will produce optimal code for this.
  421. We then have to return the xt of some word to keep FIND happy - we don't
  422. need to compile anything else, so we use the xt of NULL and return a 1
  423. instead of True - this makes FIND think it's immediate.  So NULL is
  424. executed immediately, which does precisely nothing.
  425.  
  426. The one exception to this is if the "ivar" turns out to be SELF or SUPER
  427. - in this case we need to call the nucleus word SELF which works out
  428. the right base address (this is what happened pre-2.5).  Here we keep
  429. FIND happy by pushing the xt of SELF and True, so that it sees we've
  430. found SELF.
  431. *)
  432.  
  433. : LocFind        ¥ ( str-addr -- cfa T  |  -- str-addr F )
  434.     Pfind    ?dup  ?EXIT                    ¥ Found a named parm/local
  435.     TOfind
  436.     IF                                    ¥ Found temp obj
  437.         nip                                ¥ Don't need its dic addr
  438.         postpone locReg  postpone literal  postpone +
  439.         ['] null  1   EXIT
  440.     THEN
  441.  
  442. ¥ Now we look for an ivar name
  443.  
  444.     cstate  NIF  false  EXIT  THEN        ¥ search fails if we're not compiling
  445.                                         ¥  a class
  446.  
  447. ¥ mybugtest if db then
  448.     
  449.     dup hash ^comp_class IFA_offset false  (findm)
  450.     IF                                    ¥ Found ivar
  451.         nip nip                            ¥ don't need embedded obj offs or
  452.                                         ¥  string addr
  453.         4+ w@                            ¥ ivar offset
  454.         dup $ FFFE >=                    ¥ is it SELF or SUPER (just used in
  455.                                         ¥  isolation)?
  456.         IF    drop  ['] self  true  EXIT
  457.         THEN
  458.         postpone ^base postpone literal  postpone +
  459.         ['] null  1
  460.     ELSE    false
  461.     THEN  ;
  462.  
  463.  
  464. : ILFA     ( infa -- ilfa )    4+  ;
  465.  
  466.  
  467. : ^ICLASS  ( infa -- ^class | 0 )
  468.     8 + dup @ NIF   drop 0   ELSE   @abs ?>classInMod   THEN  ;
  469.  
  470.  
  471. : IOFFS    ( infa -- ioffs )    12 + w@  ;
  472. : I#ELS    ( infa -- #els )    14 + w@  ;
  473. : IFFA     ( infa -- iffa )    inline{ 16 +}  ;
  474.  
  475.  
  476. : ^NEXTIVAR    ¥ ( infa -- infa' )
  477.     ilfa  displace  ;
  478.  
  479.  
  480. ¥                        ========================
  481. ¥                                BINDING
  482. ¥                        ========================
  483.  
  484.     0    value    OBJ_BASE
  485.     0    value    OBJ_DISPL
  486.     0    value    OBJ_LOCAL_DISPL
  487.     0    value    OBJ_IND
  488.  
  489. false    value    SELF?
  490.  
  491.  
  492. : (OBJ)        ¥ Called from within an inline method.  Passes the object's
  493.             ¥  base and displacement to Handlers to generate the correct
  494.             ¥  address.  Optimization will then apply.
  495.  
  496.     obj_base obj_displ
  497.     obj_ind  genaddr
  498.     obj_local_displ  postpone literal  postpone +  ;
  499.  
  500.  
  501. : (IX)
  502.  
  503.     (*    Called from within an inline method.  Compiles code to generate
  504.         the indexed address.
  505.         ^comp_class has been set by inl_bind to the class of the obj
  506.         we're binding to.  One tricky point is that to access the indexed
  507.         area, we have to use the dlen value in this class, not the class
  508.         of the method we're calling (which may be a superclass).  But
  509.         the obj_local_displ has already had the embedded object offset
  510.         added in (if any).  We have to ignore this, since we're using 
  511.         the object's class, not the method's.  When the method was found,
  512.         the value emb_obj_offs was set to this offset, so we subtract
  513.         it here.
  514.     *)
  515.  
  516.     ^comp_class dlen&xwid  swap
  517.     self?
  518.     IF  drop  -1  ELSE  aligned  6 +  THEN
  519.     obj_base obj_displ obj_local_displ
  520.     emb_obj_offs -
  521.     obj_ind  ^comp_class ffa w@
  522.     genxaddr  ;
  523.  
  524.  
  525. : ^BASE
  526.     compinline?
  527.     IF        (obj)
  528.     ELSE    postpone ^base
  529.     THEN  ;            immediate
  530.  
  531.  
  532. : ^ELEM
  533.     compinline?
  534.     IF        (ix)
  535.     ELSE    postpone ^elem
  536.     THEN  ;            immediate
  537.  
  538.  
  539. : OBJ    postpone ^base  ;    immediate        ¥ for backward compatibility
  540. : IX    postpone ^elem  ;    immediate        ¥ ditto
  541.  
  542.  
  543. local  EARLY_BIND  { oCfa oBase oDispl oLDispl oind slf? ¥ ^mod ptr -- }
  544.  
  545.  
  546. : INL_BIND    ¥ ( -- b )
  547.     ¥ In-line code to be compiled for this method.
  548.     ¥ But note, we don't do it if obj_base is zero, meaning that
  549.     ¥ we have put the ^obj in A0 as a temporary.  Some inline
  550.     ¥ methods could cause a clash on A0.  So in this case we
  551.     ¥ call the out-of-line code - we return true so that this
  552.     ¥ will be done by NORM_BIND.  Otherwise we return false.
  553.  
  554.     obj_base
  555.     NIF                                    ¥ Update cfa to the out-of-line code
  556.         oCfa 2+ dup c@ + aligned  -> oCfa  true
  557.     ELSE
  558.         ^comp_class  cstate  self?                ¥ Save over upcoming evaluate
  559.         slf? NIF  objClass -> ^comp_class  THEN    ¥ Set ^comp_class and cstate
  560.         true -> cstate                            ¥  so ivars are accessible
  561.         slf? -> self?
  562.         oCfa  (compinl)
  563.         -> self?  -> cstate  -> ^comp_class        ¥ Restore
  564.         false
  565.     THEN  ;
  566.  
  567.  
  568. : SETUP_MODULE_BIND
  569.     heldMod
  570.     @ @            ¥ get mod handle and dereference - addr of mod start
  571.     SAmask and  -> ^mod
  572.     ^mod 8 + -> ptr            ¥ self-rel addr of exports table
  573.     ptr @ ++> ptr            ¥ ptr -> start of table
  574.     0 -> methIndex
  575.     BEGIN
  576.         ptr @ dup 0< ?error 198
  577.         ^mod +  oCfa =
  578.     NWHILE
  579.         4 ++> methIndex  4 ++> ptr
  580.     REPEAT
  581. ;
  582.     
  583.  
  584. : NORM_BIND
  585.     heldMod IF  setup_module_bind  THEN
  586.     oCfa  (obj)  EB  ;
  587.  
  588.  
  589. :loc  EARLY_BIND        ¥ { oCfa oBase oDispl oLDispl oind slf? -- }
  590.     obj_base  obj_displ  obj_local_displ  obj_ind        ¥ Save
  591.     oBase    -> obj_base            oDispl    -> obj_displ
  592.     OLdispl    -> obj_local_displ    oind    -> obj_ind
  593.     oCfa w@  inlMk =
  594.     IF  inl_bind  ELSE  true  THEN
  595.     IF  norm_bind  THEN
  596.     -> obj_ind  -> obj_local_displ
  597.     -> obj_displ  -> obj_base                            ¥ Restore
  598. ;loc
  599.  
  600.  
  601. : BIND_TO_OBJ  { cfa ^obj offs -- }
  602.     cfa
  603.     -1                    ¥ -1 as "base" signals handlers to generate
  604.     ^obj                ¥  a normal dic addr.  We still carry the
  605.                         ¥  offs here since if we need to access the
  606.                         ¥  indexed area, we want the original obj addr,
  607.                         ¥  not some embedded object.
  608.     offs  0  false  early_bind  ;
  609.  
  610. : BIND_TO_STK        ¥ ( cfa -- )
  611.     stkObj  0 swap  false  early_bind  ;
  612.  
  613. : BIND_TO_IVAR  { cfa offs -- }
  614.     cfa  obj_base  obj_displ
  615.     obj_local_displ offs +
  616.     obj_ind  false  early_bind  ;
  617.  
  618. : BIND_TO_TMPOBJ  { cfa offs -- }
  619.     cfa
  620.     4        ¥ locReg = D4
  621.     offs
  622.     0 0 false  early_bind  ;
  623.  
  624. : BIND_TO_SELF  { cfa offs -- }
  625.     cfa  obj_base  obj_displ  offs  obj_ind  true  early_bind  ;
  626.  
  627.  
  628.  
  629. ¥                    ===========================
  630. ¥                     INITIALIZING NEW OBJECTS
  631. ¥                    ===========================
  632.  
  633. false    value    REC?        ¥ Are we compiling a record?
  634. false    value    UNION?        ¥ Are we compiling a union in a record?
  635.     0    value    UNIONOFFS    ¥ Base offset of the current union
  636.  
  637.  
  638. : INIT_OBJ   ( theClass theObj -- )
  639.  
  640. (*    Performs CLASSINIT: method on object.  Note, we quite deliberately don't 
  641.     check if the offset would put us into the indexed area of a large_obj_array.
  642.     This is because we don't want to send CLASSINIT: individually to each of the
  643.     indexed elements, but instead we just send it to the base element.  Then,
  644.     CLASSINIT: in the large_obj_array class copies this to the indexed elements.
  645. *)
  646.  
  647.     swap
  648.     ( theObj theClass )        initID swap MFA_offset true (findm)
  649.     ( theObj offs xt true )    drop     ¥ Is guaranteed to find CLASSINIT: method
  650.     ( theObj offs xt  )        >r + r>    ¥ Modify obj addr by offs (needed in case
  651.                                     ¥  method is defined in any superclass
  652.                                     ¥  but the first)
  653.     ( theObj' xt )          ex-method
  654. ;
  655.  
  656.  
  657. : MAKE_HDRS        ( #els ) { theClass theObj ¥ len wid -- }
  658.     ¥ assumes theClass is the true class address, not
  659.     ¥ the main dictionary address of an exported class
  660.     ¥ if theClass is not indexed, there should be no #els on the stack
  661.  
  662.         theClass (dlen&xwid)  -> wid  -> len            
  663.                                                 
  664.     ¥ first the xdesc (indexed area header), if indexed object
  665.         wid     IF        len aligned -> len
  666.                         theObj len +        ¥ xdesc address: after ivars
  667.         ( #els ^xdesc )    wid over w!            ¥ two bytes: indexed width
  668.         ( #els ^xdesc )    swap 1- swap 2+ !    ¥ four bytes: limit ( #els-1)
  669.                         len 12 +            ¥ offset to indexed area
  670.                                             ¥  to be put in obj header
  671.                 ELSE    6                    ¥ standard offset if not indexed
  672.                 THEN
  673.  
  674.         ¥ now the obj header itself
  675.         ( offs )    theObj 8 - w!        ¥ 2 bytes: offset to indexed area
  676.                                         ¥  calculated above
  677.                     theClass ?>maindic    ¥ don't store module addr of class!
  678.                     false -> relocChk?    ¥ obj address could be in heap!
  679.         ( ^class )    theObj 6 - reloc!    ¥ 4 bytes: relocatable class pointer
  680.                     true -> relocChk?
  681.                     -6 theObj 2- w!        ¥ 2 bytes: offset to class pointer --
  682.                                         ¥  always -6 for non-embedded object
  683. ;
  684.  
  685. forward IVSETUP
  686.  
  687. : NW_IVSETUP  { ^nway baseOffs EOoffs ¥ initEOoffs supClass supOffs -- }
  688.  
  689. (*    Sets up the groups of ivars for each superclass of the current object/ivar
  690.     being processed. One group for each super of a multiply inherited object.
  691.     Each group we call an "embedded object", which sort of describes what it is.
  692.     On entry ^nway points to the first superclass pointer in the n-way defining
  693.     the multiple inheritance. We repeat the procedure for each superclass until
  694.     the zero marking the end of the n-way is encountered. If the superclass
  695.     is the pseudoclass Meta we don't do anything since it does not have any ivars.
  696.     baseOffs is the position of the current object/ivar's data space relative
  697.     to newObject, the current top-level object being created.
  698.     EOoffs is the offset from newObject at which the current Embedded Object
  699.     starts. When an embedded object starts at a non-zero EOoffs, we put in
  700.     front of it a 2-byte offset to the class pointer. Note that if the
  701.     multiply inherited object is an ivar, there may not be a class pointer!
  702.     This doesn't matter, since it's better for multiply inherited
  703.     objects to always have the same format, wherever they are, and any attempt
  704.     to use the class pointer offset to get the (nonexistent) class pointer
  705.     will most probably be caught by our checks.
  706. *)
  707.  
  708. ¥ From Mops 2.5 on, we're now sending classinit: separately to each
  709. ¥  superclass.
  710.  
  711.     EOoffs -> initEOoffs
  712.     BEGIN
  713.         ^nway @abs ?>classInMod  -> supClass    ¥ may hold a mod
  714.         supClass  MetaAddr @abs  <>
  715.         IF
  716.             baseOffs EOoffs +  initEOoffs -    ¥ Start of dataspace of this
  717.             -> supOffs                        ¥  superclass
  718.             supClass ifa displace            ¥ Infa of first ivar of supClass
  719.             supOffs  EOoffs  ivSetup
  720.             supClass  newObject supOffs +  init_obj
  721.         THEN
  722.         ?unholdMod                                ¥ now finished with the mod
  723.         1cell ++> ^nway
  724.         ^nway @
  725.     WHILE        ¥ another class coming up - store 2-byte ^class offset first
  726.         supClass dfa w@                ¥ dlen of supClass. Faster than using DLEN
  727.         ( dlen ) aligned ++> EOoffs
  728.         EOoffs negate 8 -            ¥ ^class offset for store
  729.         EOoffs initEOoffs -            ¥ offset not already included in baseOffs
  730.         baseOffs + newObject +        ¥ final addr for store
  731.         w!
  732.         2 ++> EOoffs
  733.     REPEAT  ;
  734.  
  735.  
  736. (*    IVsetup recursively traverses the tree of nested ivar definitions in a
  737.     class, building headers and indexed area headers where necessary, and 
  738.     sending    the CLASSINIT: message to each ivar.
  739.     
  740.     On entry infa is the nfa of the first ivar in the ivar dictionary of the
  741.     object/ivar whose (sub)ivars we are to set up. The dictionary chain is
  742.     followed to the end, the last link pointing to the Nway superclass pointer.
  743.     baseOffs is the position of the current object/ivar's data space relative
  744.     to newObject, the current top-level object being created.
  745.     EOoffs is non-zero if the ivar whose subivars we are to set up is part
  746.     of an "embedded object", ie. is inherited from a superclass, and this
  747.     superclass is not the first super of the current top-level object.
  748.     This is passed on unmodified in any recursive call and used only by
  749.     NW_IVSETUP to calculate the offset to the class pointer.
  750.     When this word is called, if the object/ivar's class is in a module,
  751.     the module will be held. In some circumstances the caller still needs it.
  752.     The recursive call might require another module to be held, so we have to
  753.     save and restore any module held on entry.
  754. *)
  755.  
  756. :f IVSETUP        { infa baseOffs EOOffs ¥ ivOffs ivClass -- }
  757.  
  758.     heldMod                ¥ If class is in module it must not get unheld
  759.                         ¥  while processing so keep address on the stack
  760.     0 -> heldMod        ¥  and clear heldMod so it cannot be unheld
  761.         
  762.     BEGIN
  763.         infa @ 0>    ¥ A selector is always negative, so a
  764.                     ¥  positive value means the N-way superclass
  765.                     ¥  pointer area ( superclass adresses ),
  766.                     ¥  the endpoint of the ivar dictionary chain
  767.                     
  768.     NWHILE    ¥ build this ivar in object
  769.  
  770.         infa iffa w@ 2 and            ¥ Static ivar? -> not in obj (bit 1)
  771.         NIF    infa ioffs                ¥ Offset of ivar in owning object
  772.             baseoffs +   -> ivOffs    ¥ Position relative to newObject
  773.             infa ^iclass -> ivClass    ¥ May cause another module to be held
  774.             infa iffa w@ 1 and        ¥ Does it want headers? -> flag bit 0
  775.             IF    infa i#els dup NIF drop THEN
  776.                 ivClass
  777.                 newObject ivOffs +     ¥ address where headers must be made
  778.                 make_hdrs
  779.             THEN
  780.             ?Rdepth                    ¥ Check on recursion depth
  781.             ivClass ifa displace    ¥ Infa of first subivar in
  782.                                     ¥  chain of the currently
  783.                                     ¥  processed ivar object
  784.             ivOffs                    ¥ New base offset of subivar
  785.             0
  786.             ivSetup
  787.             ?unholdMod
  788.             ivClass  newObject ivOffs +  init_obj
  789.         THEN
  790.         infa ^nextivar -> infa
  791.     REPEAT
  792.     infa baseOffs EOoffs  NW_ivSetup    ¥ Set up superclasses
  793.     ( Heldmod )  -> HeldMod
  794. ;f
  795.  
  796.  
  797. ¥ HASHED-HDR lays down the dic header for an ivar or method.
  798. ¥ The format is:
  799. ¥
  800. ¥ 4 bytes        hash
  801. ¥ 4 bytes        link (self-relative addr of prev entry)
  802. ¥
  803. ¥ This entry has to become the first on the chain, so we pass in the
  804. ¥ addr of the chain header.
  805.  
  806. : HASHED-HDR        ¥ ( chain-hdr hash-val -- )
  807.     ,                        ¥ comma in hash value
  808.     dup displace            ¥ get abs addr of prev entry
  809.     displ,                    ¥ comma it in as self-relative addr
  810.     here 8 -  swap  displ!    ¥ update chain header
  811. ;
  812.  
  813.  
  814. forward    DIC-OBJ
  815.  
  816. : IVDEF  ( #els ) { iclass ¥ #els wid siz clOffs flags -- }
  817.         ¥ Compiles an ivar dictionary entry.  If indexed, must have
  818.         ¥ < 64K elements.  iclass is the ivar's class.  The class of
  819.         ¥ which this is an ivar, is pointed to by ^class.
  820.  
  821.     pub/priv 1 =  4 and -> flags    ¥ initial flags - set bit 2 if we're public
  822.     Mword
  823.     ivFind  ?error 117                ¥ same name as another ivar
  824.     drop
  825.     iclass xwid  -> wid                ¥ indexed width of ivar class
  826.     iclass dlen  -> siz                ¥ non-indexed size of this ivar
  827.     
  828. ¥ The initial offset is the current dlen of the class.
  829.  
  830.     ^comp_class dfa w@  -> clOffs
  831.     
  832.     ^comp_class  ifa
  833.     here  hash  hashed-hdr            ¥ dic header for ivar
  834.  
  835.     iclass ?>mainDic  reloc,
  836.     
  837. ¥ Now we need to comma in the 2-byte offset to the ivar within
  838. ¥ the class.  First we need to make some adjustments...
  839. ¥ Do we need to align the offset:
  840.  
  841.     siz 1 >                ¥ we do if the ivar size is longer than 1
  842.     wid                    ¥ or if it's indexed
  843.     or
  844.     IF                ¥ We do need to align the offset. Note that if the
  845.                     ¥ ivar class is multiply inherited with >1 superclass
  846.                     ¥ of non-zero length, the ivar size will always be >1.
  847.         clOffs aligned  -> clOffs
  848.     THEN
  849.  
  850.     iclass ffa 1+ 2 btest        ¥ general?
  851.     dup IF union? ?error 190 THEN    ¥ (can't have a general object in a union)
  852.     rec? not or                    ¥ or not in a record?
  853.     wid or                        ¥ or indexed?
  854.     IF                            ¥ Yes.  In this case the ivar will have
  855.                                 ¥  the standard 8-byte object header. So its data
  856.         8 ++> clOffs            ¥  will start 8 bytes later than otherwise.
  857.         1 or> flags                ¥ and we'll mark this in the ivar flags
  858.                                 ¥  so make_hdrs will do the right thing.
  859.     THEN
  860.     clOffs  w,
  861.  
  862.     wid
  863.     IF                ¥ Indexed. Stack has #els.  We calculate the indexed
  864.                     ¥ length of this ivar and increment clOffs.
  865.                     ¥ If we're not in a record, we also need to align the
  866.                     ¥ non-indexed size of the ivar, since the xdesc must
  867.                     ¥ be aligned. (If we're in a record, there won't be an
  868.                     ¥ xdesc.)
  869.         -> #els
  870.         siz aligned  -> siz            ¥ must align the non-indexed size
  871.         #els w,                        ¥ Add #els to ivar dic entry
  872.         #els wid *                    ¥ Get indexed length
  873.         6 +                            ¥ Add 6 for xdesc length
  874.         ++> clOffs                    ¥ Add to clOffs
  875.     ELSE            ¥ Not indexed.
  876.         0 w,
  877.     THEN
  878.     static?
  879.     IF    2 or> flags
  880.     ELSE
  881.         siz ++> clOffs                ¥ Bump clOffs by non-indexed size of ivar
  882.     THEN
  883.     flags w,
  884.  
  885. (* Now we'll update the class dLen field by whatever we're allocating for this
  886.   ivar - it will then be the offset to the next ivar.  clOffs has the offset
  887.   so far.  In the normal case, this is what goes in dLen.  If we're in
  888.   a union, we MAX it with whatever's already in dLen.  This will leave dLen
  889.   with the longest union element we've reached so far, which will be the final
  890.   value in case we hit the end of the union.
  891.   And if this ivar is static, it will live right where we are in the dic,
  892.   and not in objects of the class, so in this case we leave dLen alone.
  893. *)
  894.     union?
  895.     IF        unionOffs  clOffs  max  -> unionOffs
  896.     ELSE    
  897.         static?
  898.         NIF    clOffs  ^comp_class dfa w!
  899.         THEN
  900.     THEN
  901.  
  902. (* Now we'll check if this ivar is to be static - if so, we'll instantiate
  903.    it right here.
  904. *)
  905.  
  906.     static?  0EXIT
  907.     wid IF  #els  THEN
  908.     iclass  dic-obj
  909. ;
  910.  
  911.  
  912. ¥                    =================================
  913. ¥                            OBJECT BUILDING
  914. ¥                    =================================
  915.  
  916.  
  917. : CL>LEN ( #els ) { theClass ¥ wid len -- ( #els ) len2 }
  918.                 ¥ Gets data length of object given #els and class.
  919.     theClass dlen&xwid  -> wid  -> len
  920.     wid IF    ( #els )  dup 32766 >
  921.         IF  theClass ffa 1+ 0 btest 0= ?error 185  then
  922.          dup  wid *  6 +  len +
  923.     ELSE    len
  924.     THEN  ;
  925.  
  926.  
  927. : MAKE_OBJ        ( #els ) { theClass theObj ¥ svHeldMod -- }
  928.  
  929.     theClass ?>classinMod -> theClass    ¥ Need real class address,
  930.                                         ¥  not main dic equivalent
  931.     heldMod -> svHeldMod                ¥ If class is in module it must
  932.                                         ¥  not get unheld while processing
  933.                                         ¥  so keep the address and clear
  934.     0 -> heldMod                        ¥  heldMod so it cannot be unheld
  935.   ( #els ) theClass theObj make_hdrs    ¥ Actually #els is optional element
  936.                                         ¥  on the stack
  937.         
  938.     theObj -> newObject                    ¥ base address used by ivsetup
  939.     theClass ifa displace  0 0 ivSetup
  940.     svHeldMod -> heldMod  ?unholdMod    ¥ held module (if any) no longer needed
  941.     theClass theObj init_obj            ¥ do a latebound CLASSINIT:
  942. ;                                        ¥  on the object
  943.  
  944.  
  945. :f DIC-OBJ  ( #els ) { theClass ¥ ^obj -- }
  946.                 ¥ Builds an object in the dictionary.
  947.     here >obj -> ^obj                ¥ Where obj data will start
  948.     theClass  cl>len
  949.     8 +  aligned                    ¥ Required length
  950.     dup room >  ?error 186            ¥ "Not enough room"
  951.       reserve                            ¥ Allocate space for object
  952.     theClass  ^obj  make_obj        ¥ Set up the object
  953.     align-dp  ;f
  954.  
  955.  
  956. :f BLD        ¥ ( (#els) -- )    ¥ Builds an object.
  957.                             ¥ Gets called when a class name
  958.                             ¥  is executed
  959.     r> 4-    ¥ Trick! pulling the return address from the stack
  960.             ¥  causes exit to skip the rest of the calling word,
  961.             ¥  which is actually a class definition and does not
  962.             ¥  contain any more executable code.
  963.             ¥  Subtracting 4 gives the class cfa, needed later
  964.             ¥ Note: because of this trick we can't use locals here!
  965.  
  966.     cstate    IF        ( theClass )  ivDef        ¥ Build an ivar
  967.             ELSE    create_obj                ¥ Create object header - returns
  968.                                             ¥  its data address when called
  969.                     ( theClass )  dic-obj
  970.             THEN
  971. ;f
  972.  
  973.  
  974.  
  975.  
  976. : ]C    true  -> cstate ;        immediate
  977. : C[    false -> cstate ;        immediate
  978.  
  979.  
  980. : HASH,        ¥ Compiles hashed word for name at here
  981.     @word  hash ,  ;
  982.  
  983.  
  984. ¥                    ============================
  985. ¥                            :CLASS  etc.
  986. ¥                    ============================
  987.  
  988.  
  989. ¥ Here we set up some quantities so that we can send messages to SELF
  990. ¥ or SUPER.  These are treated syntactically as ivars, so to implement
  991. ¥ them we actually set up dummy ivars SELF and SUPER.
  992.  
  993. ¥ When we're processing a :CLASS definition, we plug the appropriate
  994. ¥ addresses into these ivars.  ^SELF is a word defined to return the
  995. ¥ addr of the dummy ivar SELF, so we can do the plugging.
  996. ¥ In the case of SUPER, there may be several superclasses, so we have
  997. ¥ to go through a class descriptor, since that's the only place we look
  998. ¥ for an n-way (a set of addresses).  So we set the "class" of SUPER
  999. ¥ to a dummy class SUPCL, which has no ivars or methods (so the search
  1000. ¥ will pass right on by), and plug the superclass pointer of SUPCL to
  1001. ¥ point to the current n-way for the superclasses of the class we're
  1002. ¥ defining.
  1003.  
  1004.    0    value    (^SELF)
  1005.    
  1006. : ^SELF  ['] (^self)  displace  ;
  1007.  
  1008. create    SUPCL                    ¥ dummy superclass
  1009.     classCode  here 2 -  w!
  1010.     classMk ,
  1011.     32 reserve                    ¥ methods links - no methods
  1012.     0,                            ¥ ivar link - patched at :CLASS time
  1013.     0,                            ¥ data len, indexed width
  1014.     0,                            ¥ flags, xdispl-offs
  1015. ¥ don't need any more!
  1016.  
  1017.  
  1018. ¥ META is the super class of Object - top of all inheritance
  1019.  
  1020. : META    reveal
  1021.     [                            ¥ Note, we're still at the cfa
  1022.     drop                        ¥ Drop the security marker left by colon
  1023.     classCode  here 2 -  w!
  1024.     classMk ,                    ¥ class marker goes here
  1025.     32 reserve                    ¥ methods links - no methods
  1026.     0,                            ¥ ivar link - set to SUPER below
  1027.     0,                            ¥ data len, indexed width
  1028.     0,                            ¥ flags, indexing offs
  1029.     0,                            ¥ super pointer
  1030.  
  1031. ¥ Now we set up the SELF and SUPER pseudo-ivars.  We set them up exactly
  1032. ¥ as if they'd been declared as regular ivars in META.  But note we don't
  1033. ¥ set up any fields past the "offset" field, since they're irrelevant.
  1034.  
  1035. create    SUP                        ¥ this is so we can tick it at SuperRef below.
  1036.  
  1037.     here                        ¥ ready for SELF link below
  1038.     hash, SUPER
  1039.     0,                            ¥ empty link
  1040.     ' supCl  reloc,                ¥ ^class is dummy supCl (reloc addr reqd)
  1041.     $ FFFE  w,                    ¥ "offset" FFFE means SUPER
  1042.  
  1043.  
  1044.     here
  1045.     hash, SELF
  1046.     swap  displ,                ¥ link (points to SUPER)
  1047.     0,                            ¥ ^class (gets patched at :CLASS time)
  1048.     $ FFFF  w,                    ¥ "offset" FFFF means SELF
  1049.  
  1050.  
  1051. dup    ' (^self)    displ!            ¥ ^SELF will now return addr of SELF ivar
  1052.     ' meta ifa    displ!
  1053.  
  1054. ' meta    metaAddr reloc!            ¥ patches so NW_IVSETUP can compare
  1055.                                 ¥ to decide if the end of the superclass
  1056.                                 ¥ chain has been reached
  1057.  
  1058.  
  1059.     0    value    THISM
  1060.     0    value    SUPERM
  1061. false    value    1SUPER?
  1062.  
  1063.  
  1064. : :CLASS        immediate
  1065.     ?exec  header  classCode w,
  1066.     here -> ^comp_class
  1067.     0 -> pub/priv  0 -> #1st  0 -> #last
  1068.     false -> rec?  false -> union?  false -> static?
  1069.     307  ;
  1070.  
  1071.  
  1072. : MERGE_INFO  { ^sup ivlen ¥ ^wid wid prevWid -- dlen }
  1073.     ^sup dlen&xwid  -> wid        ¥ indexed width of this superclass
  1074.     ^sup ffa 1+ c@ 5 and        ¥ Merge "general" and "indexed" flags with
  1075.     ^comp_class ffa 1+  cset    ¥  what we have already
  1076.     wid  0EXIT                    ¥ If this superclass not indexed, we're done
  1077.     
  1078. ¥ This class is indexed - we need to check if prev classes were indexed
  1079. ¥  and make sure the widths are compatible.
  1080.  
  1081.     ^comp_class dfa 2+  -> ^wid    ¥ Addr of wid field in class we're building
  1082.     ^wid w@  -> prevWid            ¥ Get previous width
  1083.     wid 32760 u>                ¥ "indexed width" of 32766/7 really means
  1084.     IF                            ¥  obj_array.
  1085.         prevWid                    ¥ In this case if we already have a width,
  1086.         IF        prevWid -> wid    ¥  we use that,
  1087.         ELSE    wid
  1088.                 ivlen  -> wid    ¥ otherwise current ivar len becomes the width.
  1089.  
  1090.             ( old wid ) 32766 =
  1091.                 IF        ¥ large_obj_array - mark boundary between ivars
  1092.                         ¥  we are/aren't mapping to the indexed area
  1093.                     ivlen aligned  ^comp_class xoffa w!
  1094.                     wid aligned 2+  -> wid    ¥ and allow for ^class offset
  1095.                                             ¥  field before each element
  1096.                 THEN
  1097.         THEN
  1098.     THEN
  1099.     prevWid
  1100.     NIF     wid  ^wid w!        ¥ If no prev width, set width & we're done
  1101.     ELSE    prevWid wid <>  ?error 88        ¥ "Incompatible indexed widths"
  1102.     THEN
  1103. ;
  1104.  
  1105.  
  1106. local    (SUP)   { ¥ ivlen ^nway ^sup ^newClass thisLen -- }
  1107.  
  1108. : NEXT_SUPER    ( cfa -- )
  1109.     chkClass  -> ^sup
  1110.     ^sup reloc,                        ¥ Add ^class to n-way
  1111.     ^sup ivlen merge_info   -> thisLen
  1112.     #sup IF                            ¥ If this is a subsequent class,
  1113.         ivlen aligned  2+  -> ivlen    ¥  align and allow for ^class offset
  1114.     THEN
  1115.     thisLen ++> ivlen                ¥ And add ivar length of new class
  1116.     1 ++> #sup  ;
  1117.  
  1118.  
  1119. : SUPERS_LOOP
  1120.     BEGIN                        ¥ Loop over superclasses:
  1121.         '                        ¥ cfa of next item on list
  1122.         }or)? IF  drop  EXIT  THEN
  1123.         ( cfa )  next_super            ¥ handle next superclass
  1124.         1super?  ?EXIT                ¥ Yerk has only one superclass
  1125.     AGAIN  ;
  1126.  
  1127.  
  1128. :loc  (SUP)
  1129.     307 ?pairs                        ¥ Make sure we're in the right place
  1130.     DP -> ^newClass
  1131.     classMk ,  classSize 4- reserve    ¥ Space for class record
  1132.     DP -> ^nway                        ¥ n-way for superclasses will
  1133.     0 -> ivlen  0 -> #sup            ¥  start here
  1134.     ^newClass 4+ 32 bounds
  1135.     DO  ^nway  i displ!  4 +LOOP    ¥ point methods links to nway
  1136.     ^nway ^newClass IFA  displ!        ¥ and ivars link
  1137.     false -> relocChk?
  1138.     supers_loop                        ¥ Loop over superclasses
  1139.     0,                                ¥ Terminate n-way
  1140.     ['] supCl 4+ 32 bounds
  1141.     DO  ^nway  i displ!  4 +LOOP    ¥ we point the method and ivar links
  1142.     ^nway  ['] supCl IFA  displ!    ¥  in supcl to the n-way
  1143.  
  1144.     ^comp_class xoffa w@  ['] supCl xoffa w!    ¥ and set xoffs in supCl
  1145.  
  1146.     ivlen ^comp_class dfa w!        ¥ Set total ivar length
  1147.     ^comp_class  ^self 8 +  reloc!    ¥ Store ^class in SELF
  1148.     true -> relocChk?
  1149.     postpone ]c                        ¥ In a class definition
  1150.     308
  1151. ;loc
  1152.  
  1153.  
  1154. : SUPER{        false -> 1super?   (sup)  ;        immediate
  1155. : SUPER(        postpone super{  ;                immediate
  1156.  
  1157. : <SUPER    true -> 1super?  (sup)    ;            immediate
  1158.             ¥ For compatibility with Yerk -- only looks for 1 superclass
  1159.             
  1160.             
  1161. : (;CL)
  1162.     postpone [   postpone c[
  1163.     0 ^self 8 + !  ;
  1164.  
  1165.  
  1166. : ;CLASS
  1167.     (;cl)  308 ?defn  ;            immediate
  1168.  
  1169.  
  1170.    1    value    DFRSELID    ¥ 1 means no late bind going on - otherwise it's
  1171.                                ¥  the selector we're late binding with
  1172. true    value    SLCTRS?        ¥ Set false to treat selectors as normal words
  1173.                             ¥  for full ANSI compatibility
  1174.  
  1175. : SEL?        ¥ ( addr -- addr b )  True if word at addr is a selector xxx:
  1176.     slctrs?  NIF  false  EXIT  THEN
  1177.     dup  count tuck  1- + c@  & :  =
  1178.     swap 1 >  and  ;
  1179.  
  1180.  
  1181. : GETSELECT            ¥ Gets a selector from the input stream
  1182.     mword
  1183.     sel?  not ?error 124
  1184.     hash
  1185.     1 -> dfrSelID  ;
  1186.  
  1187.  
  1188. ' null    vect    GET1ST&LAST
  1189. ' null    vect    DoCall1ST
  1190. ' null    vect    DoCallLast
  1191.  
  1192.  
  1193. : M_HEADER  { selID -- }    ¥ Builds a method header and entry sequence.
  1194.                             ¥ Note: also called from the assembler.
  1195.     selID ^comp_class MFA  selID  hashed-hdr    ¥ Build header
  1196.     drop                            ¥ drop extra selID (needed by MFA)
  1197.     pub/priv -1 =  1 and  w,        ¥ public/private flag (default is public)
  1198.     here -> thisM                    ¥ Remember method cfa
  1199.     Mentry  ;                        ¥ Compile the entry sequence
  1200.  
  1201.  
  1202.  
  1203. : :M { ¥ selID -- }     immediate        ¥ Start compiling a method.
  1204.     true -> method?                    ¥ Used by Handlers
  1205.     ?class  305
  1206.     rec? ?error 191                    ¥ unmatched '{' in ivar list
  1207.     0 -> superM
  1208.     getSelect -> selID
  1209.     10 -> cstate                    ¥ Means we've read :m, no call_1st yet
  1210.     selID ^comp_class MFA_offset true (findm)        ¥ is method already defined?
  1211.     IF
  1212.         -> superM
  1213.         warnings?
  1214.         IF    cr  0 -> out
  1215.             here count type type# 182         ¥ "Method redefined"
  1216.         THEN
  1217.         heldMod 
  1218.         NIF  superM ^comp_class > ?error 183  THEN
  1219.                                             ¥ - but if in same class, error
  1220.         drop
  1221.     THEN
  1222.     get1st&last  ?unHoldMod
  1223.     selID m_header                    ¥ Build method header
  1224.     #1st #last + IF  thisM 1- 7 bset  THEN
  1225.     $ 42 -> obj_base                ¥ $ 42 means reg A2 - our obj base
  1226.     0 -> obj_displ                    ¥ For any inline method calls
  1227.     (:)                                ¥ Start to compile the method
  1228.     doCall1st  ;                    ¥ Compile any Call1st calls first
  1229.  
  1230.  
  1231. : ;M
  1232.     (;)
  1233.     #last  IF  true -> method?  doCallLast  defnEnd  false -> method?  THEN
  1234.     0 -> #1st  0 -> #last
  1235.     305 ?defn  ;        immediate
  1236.  
  1237.  
  1238. ¥    ============== Local sections for methods ==============
  1239.  
  1240. ¥ These function just like regular local sections.  The implementation
  1241. ¥ is nearly the same.
  1242.  
  1243.     0    value    MLOC_ADDR
  1244.  
  1245.  
  1246. : MLOCAL        ¥ Starts a local section for methods
  1247.     local?  ?error 93  1 -> local?        ¥ We change it to the normal -1
  1248.                                         ¥ as soon as "{" is read.
  1249.     postpone :m
  1250.     postpone [
  1251.     here -> mloc_addr  10 allot        ¥ Like a forward definition.  We
  1252.                                     ¥ save the addr to patch and leave
  1253.                                     ¥ room for the JMP instrn which will
  1254.                                     ¥ be planted by (patch) below.
  1255.     private  ;
  1256.  
  1257.  
  1258. : :MLOC        immediate
  1259.     public  ?loc  getSelect drop  95
  1260.     here  mloc_addr  (patch)    ¥ Like :F
  1261.     #PL  IF  PLentry  THEN
  1262.     false -> local?                ¥ We do this here so any EXITs
  1263.                                 ¥  tidy everything up properly
  1264.     postpone ]  ;
  1265.  
  1266.  
  1267. : ;MLOC        immediate
  1268.     (;)  95 ?pairs                ¥ As local? is now false, everything else
  1269.     305 ?defn  ;                ¥ gets tidied up by (;)
  1270.  
  1271.  
  1272.  
  1273. ¥    ================   INDEXED, GENERAL etc.   =================
  1274.  
  1275. ¥ These are words which can appear in a class declaration, in the
  1276. ¥ position
  1277.  
  1278. ¥  :class someClass super{ someSuper }   general
  1279.  
  1280. ¥ They add attributes to the class.
  1281.  
  1282.  
  1283. : INDEXED        ¥ ( width -- )  Sets a class and its subclasses to indexed
  1284.     ?class  ^comp_class dfa 2+  w!  ;
  1285.  
  1286. : LARGE        ¥ Sets the "large" option on an indexed class, allowing
  1287.             ¥ the number of elements to be greater than 32K.
  1288.  
  1289.     ?class  ^comp_class ffa 1+  0 bset  ;
  1290.  
  1291.  
  1292. : GENERAL
  1293.  
  1294. (* Sets the "general" option on a class, which will force an ivar of that class
  1295.    to be a general object with a class pointer (so it can be late-bound to) even
  1296.    if it's within a record.  Normally you should just not put such ivars in a
  1297.    record, but using GENERAL gives a bit of extra security, for classes for which
  1298.    you know that they will definitely be late-bound to.  (An attempt to late-bind
  1299.    to an ivar without a class pointer will give the "not an object" error at run
  1300.    time, which isn't easy to track down.)
  1301.    Note that indexed classes are always general anyway.  Also if there's a message
  1302.    sent to [self] somewhere in one of the methods, we know that the class *must*
  1303.    be general, so in this case we simply set the general attribute.
  1304. *)
  1305.     ?class  ^comp_class ffa 1+  2 bset  ;
  1306.  
  1307.  
  1308. ¥                    ===========================
  1309. ¥                            SELECTORS
  1310. ¥                    ===========================
  1311.  
  1312. ¥ First, here are the special-purpose things which can follow a selector.
  1313. ¥ These can't appear in isolation.
  1314.  
  1315. ¥ We allow ** and [] as synonyms of [ ] to late-bind to whatever is on the
  1316. ¥ stack.  Note:  [] is used in JForth.
  1317.  
  1318. ¥ We also allow [self] as a synonym of [ self ]
  1319.  
  1320. : **        83 die  ;        ¥ "Has no meaning unless preceded by a selector"
  1321. : []        83 die  ;
  1322. : [SELF]    83 die  ;
  1323. : SUPER>    83 die  ;
  1324. : IVAR>        83 die  ;
  1325. : CLASS_AS>    83 die    ;
  1326.  
  1327.  
  1328. : ]
  1329.     hide  dfrSelID  1 = IF   postpone ]  EXIT  THEN        ¥ if no late bind, this is a
  1330.                                                         ¥  standard Forth ]
  1331.     dfrSelID NIF  187 die  THEN            ¥ late bound pubilc ivar reference
  1332.                                          ¥  not implemented yet!
  1333.     251 ?pairs
  1334.     state
  1335.     IF        postpone (defer)  dfrSelID ,
  1336.     ELSE    dfrSelID  send
  1337.     THEN
  1338.     1 -> dfrSelID  ;        immediate
  1339.  
  1340.  
  1341. 100        constant    pubIvarTyp        ¥ &&& temp
  1342. false    value        need_class?
  1343.  
  1344. false    value        implicit_late_bind?        ¥ true for pre-2.7 auto-late-bind
  1345.                                             ¥  to locals or values
  1346.  
  1347.  
  1348. (* REFTOKEN  ( -- <various> type )
  1349.    is called when we've parsed a selector - it determines the type of the
  1350.    following word.
  1351.    
  1352.    The order of checking determines the priority of names.  Up to 2.6 we
  1353.    checked for locals first, but this was a bad idea since a local could
  1354.    have the same name as an object, and implicit late binding to locals
  1355.    was legal.  This wouldn't show up until a crash at run time.  So now we
  1356.    check for temp objects, then ivars, then locals, IF implicit_late_bind?
  1357.    is true.
  1358.  
  1359.    <various> will be the cfa of whatever came after the selector, or
  1360.    ( ^ivar offs xdispl-offs ) for ivars and temp objects (which are treated as ivars
  1361.    of the class Dummy).
  1362. *)
  1363.  
  1364. : REFTOKEN        ¥ ( -- <various> type )
  1365.  
  1366.     false -> need_class?
  1367.     Mword                                    ¥ grab next word
  1368.     TOfind    IF  tmpObjTyp    EXIT  THEN        ¥ check for temp object
  1369.     IVfind    IF  ivarTyp        EXIT  THEN        ¥ check for ivar
  1370.     
  1371.     implicit_late_bind?
  1372.     IF    Pfind    IF  locTyp    EXIT  THEN        ¥ check for named parm/locals
  1373.     THEN
  1374.  
  1375.     ( here )  dup thread dup @ +  (find)  0=  ?error 125
  1376.     dup ['] **            =  IF  lbTyp                            EXIT  THEN
  1377.     dup ['] []            =  IF  lbTyp                            EXIT  THEN
  1378.     dup ['] [            =  IF  bktTyp                            EXIT  THEN
  1379.     dup ['] [self]        =  IF  lbSelfTyp                        EXIT  THEN
  1380.     dup ['] super>        =  IF  superTyp                            EXIT  THEN
  1381.     dup ['] ivar>        =  IF  pubIvarTyp                        EXIT  THEN
  1382.     dup ['] class_as>    =  IF  true -> need_class?  classTyp    EXIT  THEN
  1383.     dup hdlr
  1384.     CASE
  1385.         objCode        OF    >obj  objTyp    ENDOF
  1386.         classCode    OF    classTyp        ENDOF
  1387.         -90            OF    classTyp        ENDOF        ¥ Exported class
  1388.         objPtrCode    OF    objPtrTyp        ENDOF
  1389.         valCode        OF    valTyp            ENDOF
  1390.         wordCode    OF    wordTyp            ENDOF
  1391.         vectCode    OF    wordTyp            ENDOF
  1392.                                 ¥ Note: here we can treat vectors as words.
  1393.  
  1394.         126 die                        ¥ "Not an object name"
  1395.     ENDCASE
  1396.  
  1397. ¥ but if we got wordTyp or valTyp, it's only legal if implicit_late_bind?
  1398. ¥  is true
  1399.     implicit_late_bind?  ?EXIT        ¥ all OK - done
  1400.     dup wordTyp =  over valTyp =  or
  1401.     IF  126 die  THEN
  1402. ;
  1403.     
  1404.  
  1405.  
  1406. ¥ These words handle the binding of a selector to whatever follows it.
  1407.  
  1408. (*    FIX_PIVAR does the housekeeping for accessing a public ivar.  When we
  1409.     encounter  msg: ivar>  then we store the selector in pivSel, and the
  1410.     hashed ivar name in pivar.  We then continue with a zero "selector",
  1411.     which signals that it's a public ivar access, and leads to us being
  1412.     called back here to fix everything up once we've got the class in which
  1413.     the ivar lives.
  1414. *)
  1415.  
  1416. : FIX_PIVAR  { ^class in_class? ¥ ^ivar offs xdispl-offs -- cfa offs xdispl-offs }
  1417.  
  1418.     ^class ?>classInMod -> ^class
  1419.  
  1420.     pivar ^class <findIV>            ¥ ( ^ivar offs xdispl-offs true  OR  false )
  1421.     0= ?error 192                    ¥ "ivar not found"
  1422.     -> xdispl-offs  -> offs  -> ^ivar
  1423.     ^ivar iffa w@                     ¥ get ivar flags
  1424.     dup 4 and 0=    ?error 193        ¥ ivar not public
  1425.     2 and                            ¥ static flag
  1426.     in_class?
  1427.     IF        0=  ?error 197            ¥ ivar not static
  1428.     ELSE    ?error 195                ¥ wrong syntax for public static ivar
  1429.     THEN
  1430.  
  1431. ¥ now we find the method in the ivar's class
  1432.  
  1433.     pivSel ^ivar  ivFindm drop        ¥ %%% don't worry about large_obj_arrays
  1434.                                     ¥  which are ivars yet!
  1435.   ( cfa  offs-within-ivar )
  1436.     in_class?
  1437.     IF            ¥ for public static ivars, the "offset" we return is
  1438.                 ¥  actually the ivar's real data address.
  1439.         drop ^ivar static_ivar_offs +  -> offs
  1440.     ELSE
  1441.         ++> offs
  1442.      THEN
  1443.      offs  xdispl-offs
  1444. ;
  1445.  
  1446.  
  1447. ¥ PUBLIC_STATIC_IVAR_REF handles a message bind to a public static ivar
  1448. ¥ (done via the  msg: ivar> in_class someClass  syntax)
  1449.  
  1450. : PUBLIC_STATIC_IVAR_REF
  1451.     refToken
  1452.     classTyp <>  ?error 196            ¥ class name must follow in_class
  1453.     true  fix_pivar drop            ¥ %%% don't worry about large_obj_arrays
  1454.                                     ¥  which are public static ivars yet!
  1455.     0  bind_to_obj
  1456. ;
  1457.  
  1458.  
  1459. ¥ OBJREF handles a reference to a normal object.
  1460.  
  1461. : OBJREF  { selID ^obj ¥ cfa offs xdispl-offs -- }
  1462.  
  1463.     selID
  1464.     IF    selID ^obj  objFindm
  1465.     ELSE                ¥ it's a public ivar reference in the referenced object
  1466.         ^obj >class  false  fix_pivar
  1467.     THEN
  1468.  
  1469.   ( cfa offs xdispl-offs )  -> xdispl-offs  -> offs  -> cfa
  1470.     xdispl-offs
  1471.     IF    ^obj xdispl-offs +  lit-addr
  1472.         postpone dup postpone @ postpone +
  1473.         offs IF  offs postpone literal  postpone +  THEN    ¥ will normally be zero
  1474.         cfa bind_to_stk  EXIT
  1475.     THEN
  1476.  
  1477.      cfa ^obj offs bind_to_obj
  1478. ;
  1479.  
  1480.  
  1481. ¥ IVARREF handles a reference to an ivar.
  1482.  
  1483. : IVARREF  { selID ^ivar offs xdispl-offs ¥ cfa stat? -- }
  1484.  
  1485.     heldMod  0 -> heldMod                ¥ save
  1486.     offs  $ FFFE >=  -> selfRef?        ¥ if self or super.  Allows private
  1487.                                         ¥ methods to be found by (findm)
  1488.     selfRef?
  1489.     IF  supers_to_skip -> sups2skip        ¥ sups2skip is interrogated by (findm).
  1490.                                         ¥  This must only be done if self or
  1491.                                         ¥  super is the target.
  1492.         0 -> offs                        ¥ "real" offset is zero
  1493.     ELSE
  1494.         ^ivar iffa w@ 2 and  -> stat?    ¥ static ivar?
  1495.     THEN
  1496.  
  1497.     selID
  1498.     IF    selID ^ivar ivFindM            ¥ %%% don't worry about large_obj_arrays
  1499.                                     ¥  which are ivars yet!
  1500.         selfRef? IF -> xdispl-offs  ELSE drop THEN
  1501.  
  1502.         ++> offs                    ¥ add embedded obj base offs to ivar offs
  1503.         -> cfa
  1504.         0 -> sups2skip  0 -> supers_to_skip
  1505.  
  1506.         selfRef?
  1507.         IF    xdispl-offs
  1508.             IF    postpone ^base  xdispl-offs postpone literal  postpone +
  1509.                 postpone dup postpone @ postpone +
  1510.                 cfa  bind_to_stk
  1511.             ELSE
  1512.                 cfa offs bind_to_self  false -> selfRef?
  1513.             THEN
  1514.             ?unholdMod  -> heldMod   EXIT
  1515.         THEN
  1516.  
  1517.     ELSE            ¥ it's a public ivar reference within the referenced ivar
  1518.         ^ivar ^iclass false  fix_pivar drop        ¥ %%% don't worry about large_obj_arrays
  1519.                                                 ¥  which are ivars yet!
  1520.         ++> offs  -> cfa
  1521.     THEN
  1522.  
  1523.     stat?
  1524.     IF    cfa ^ivar static_ivar_offs  bind_to_obj
  1525.         ?unholdMod  -> heldMod  EXIT
  1526.     THEN
  1527.     
  1528.     xdispl-offs
  1529.     IF    postpone ^base  xdispl-offs postpone literal  postpone +
  1530.         postpone dup postpone @ postpone +
  1531.         offs IF  offs postpone literal  postpone +  THEN    ¥ will normally be zero
  1532.         cfa  bind_to_stk
  1533.     ELSE
  1534.         cfa offs  bind_to_ivar
  1535.     THEN
  1536.     ?unholdMod  -> heldMod
  1537. ;
  1538.  
  1539.  
  1540. ¥ OP/CL is common code factored out of objPtrRef and classRef, which
  1541. ¥ are very similar.
  1542.  
  1543. : OP/CL  { selID ^class ¥ cfa offs xdispl-offs -- }
  1544.     selID
  1545.     IF    selID ^class clFindm
  1546.     ELSE
  1547.         ^class  false  fix_pivar
  1548.     THEN
  1549.     -> xdispl-offs  -> offs  -> cfa
  1550.  
  1551.     xdispl-offs
  1552.     IF    xdispl-offs postpone literal  postpone +
  1553.         postpone dup postpone @ postpone +
  1554.     THEN
  1555.     
  1556.     offs postpone literal  postpone +
  1557.     cfa bind_to_stk
  1558. ;
  1559.  
  1560.  
  1561. ¥ OBJPTRREF handles a reference to an object pointer.
  1562.  
  1563. : OBJPTRREF  { selID OP-cfa ¥ ^class cfa offs xdispl-offs -- }
  1564.     OP-cfa (comp)                    ¥ Compile a fetch of the OP-cfa,
  1565.                                     ¥  giving ^obj at run time
  1566.     OP-cfa 4+ @  0= ?error 86        ¥ "ObjPtr hasn't had a class specified"
  1567.     OP-cfa 4+ @abs  -> ^class
  1568.     ^class hdlr -90 =
  1569.     IF                                ¥ Class is exported
  1570.         ^class 6 + wdisplace        ¥ Addr of module
  1571.         compmod =  ?error 84        ¥ It's the module we're compiling -
  1572.                                     ¥  this is a no-no, since the ObjPtr
  1573.                                     ¥  reference will use the OLD module!
  1574.         ^class  ?>classInMod -> ^class
  1575.     THEN
  1576.     selID ^class  OP/cl
  1577. ;
  1578.  
  1579.  
  1580. ¥ CLASSREF handles a reference to a class - this means use the object
  1581. ¥  whose addr is on the stack, but ASSUME it is of the given class
  1582. ¥  and early bind, without checking.
  1583. ¥ The code is very similar to objPtrRef, naturally enough.
  1584.  
  1585. : CLASSREF { selID ^class ¥ cfa offs xdispl-offs -- }
  1586.     need_class? IF  '  chkClass  -> ^class  false -> need_class?  THEN
  1587.     selID ^class  OP/cl
  1588. ;
  1589.  
  1590.  
  1591. ¥ TMPOBJREF handles a reference to a temp object.
  1592.  
  1593. : TMPOBJREF  { selID ^tmpObj offs ¥ svHeldMod cfa xdispl-offs -- }
  1594.  
  1595.     heldMod -> svHeldMod  0 -> heldMod
  1596.     selID
  1597.     IF    selID ^tmpObj ivFindM
  1598.     ELSE
  1599.         ^tmpObj 8 + @abs  false  fix_pivar
  1600.     THEN
  1601.     -> xdispl-offs  ++> offs  -> cfa
  1602.  
  1603.     xdispl-offs
  1604.     IF    postpone locReg
  1605.         xdispl-offs postpone literal  postpone +
  1606.         postpone dup postpone @ postpone +
  1607.         offs IF  offs postpone literal  postpone +  THEN    ¥ will normally be zero
  1608.         cfa  bind_to_stk
  1609.     ELSE
  1610.          cfa offs  bind_to_tmpObj
  1611.         svHeldMod -> heldMod
  1612.     THEN
  1613. ;
  1614.  
  1615.  
  1616. ¥ SuperRef handles the  msg: super> someSuper  construct.
  1617.  
  1618. : SUPERREF { selID ¥ ^nway namedClass ^nway' cnt -- }
  1619.     ?class                            ¥ Must be compiling a class
  1620.     '  -> namedClass                ¥ get named class xt
  1621.     ^comp_class sfa -> ^nway
  1622.     ^nway -> ^nway'  0 -> cnt
  1623.     BEGIN
  1624.         ^nway' @ 0= ?error 120            ¥ "superclass" not found
  1625.         ^nway' @abs namedClass =
  1626.     NWHILE
  1627.         1cell ++> ^nway'  1 ++> cnt
  1628.     REPEAT
  1629.     cnt -> supers_to_skip
  1630.     selID  ['] sup  $ FFFE  0  ivarRef        ¥ equivalent to msg: super
  1631. ;
  1632.  
  1633. forward COMPREF
  1634.  
  1635. ¥ PubIvarRef handles the  msg: ivar> someIvar IN someObj  construct, to
  1636. ¥  send a message directly to a public ivar in an object.  At this point
  1637. ¥  we've just read "ivar>".
  1638.  
  1639. : PUBIVARREF  { selID ¥ addr len ^class ^ivar -- }
  1640.     selID -> pivSel                    ¥ save selID being sent to the ivar
  1641.     mword hash  -> pivar            ¥ parse ivar name
  1642.     mword count  -> len  -> addr
  1643.     addr len  " IN" s=
  1644.     IF    0                 ¥ dummy "selID" for compRef (not a legal selector)
  1645.         compRef            ¥ handle whatever object comes after IN.  The
  1646.                         ¥  zero selector signals that a public ivar in the
  1647.                         ¥  indicated object is to be accessed - real selectors
  1648.                         ¥  can't ever be zero.  This will lead to fix_pivar
  1649.                         ¥  being called to complete the job.
  1650.     ELSE
  1651.         addr len " IN_CLASS" s=
  1652.         IF        public_static_ivar_ref
  1653.         ELSE    true ?error 194        ¥ "wrong syntax for public ivar"
  1654.         THEN
  1655.     THEN
  1656. ;
  1657.  
  1658.  
  1659. ¥ LBselfRef handles messages to [self] - i.e. late bound to Self.
  1660.  
  1661. : LBSELFREF
  1662.     postpone self  postpone (defer)  ,
  1663. ;
  1664.  
  1665. ¥ Since any class with a late-bound message to self MUST be general, we
  1666. ¥  used to force it to general at this point.  But since class Object
  1667. ¥  now has a call to [self] in deep_classinit:, this got us rapidly
  1668. ¥  into crash territory!  So just remember the general when it's needed.
  1669.  
  1670.  
  1671. : COMPDFR    ¥ (selID cfa -- )
  1672.     (comp)  postpone (defer)  ,  ;
  1673.  
  1674.  
  1675. ¥ Now here are the main words which compile the selector bindings.
  1676.  
  1677. ¥ CompRef operates at compile time - it compiles a selector bind.
  1678.  
  1679. :f COMPREF        ¥ ( selID -- )
  1680.  
  1681.     refToken    ¥ ( selID <various> type )
  1682.                 ¥    <various> will be the cfa of whatever came after the selector,
  1683.                 ¥    or ( offset ^ivar ) for ivars and temp objects (which are
  1684.                 ¥    treated as ivars of the class Dummy).
  1685.  
  1686.     CASE
  1687.         objTyp        OF  objRef                            ENDOF
  1688.         ivarTyp        OF    ivarRef                            ENDOF
  1689.         objPtrTyp    OF  objPtrRef                        ENDOF
  1690.         tmpObjTyp    OF  tmpObjRef                        ENDOF
  1691.         classTyp    OF    classRef                        ENDOF
  1692.  
  1693. ¥ These next 3 can only come up if implicit_late_bind? is true:
  1694.         valTyp        OF  compdfr                            ENDOF
  1695.         locTyp        OF  compdfr                            ENDOF
  1696.         wordTyp        OF  compdfr                            ENDOF
  1697.  
  1698.         lbTyp        OF  drop  postpone (defer)  ,        ENDOF
  1699.         lbSelfTyp    OF  drop  LBselfRef                    ENDOF
  1700.         bktTyp        OF  drop  -> dfrSelID  251            ENDOF
  1701.         superTyp    OF    drop  superRef                    ENDOF
  1702.         pubIvarTyp    OF    drop  pubIvarRef                ENDOF
  1703.  
  1704.         82 die                        ¥ "Selector can't be used on that"
  1705.         
  1706.     ENDCASE  ;f
  1707.  
  1708.  
  1709. (*
  1710. RunRef is the execution mode equivalent - it executes a selector bind.
  1711. We do this simply by compiling it in a buffer then executing it there.
  1712. This replaces the earlier scheme where we had to separately handle each
  1713. case as for compRef - this was a Neon carryover.
  1714.  
  1715. While we're compiling in the buffer, we save the DP on the return stack,
  1716. then restore it before executing what we compiled (since it might do some
  1717. compiling itself).  This isn't long, but it's a bit tricky:
  1718. *)
  1719.  
  1720.     variable    runRefBuf    56 reserve    ¥ allows 4 nested binds - worst case
  1721.                                         ¥  14 bytes each
  1722. 0    value        bufPtr
  1723. 0    value        hiDP
  1724.  
  1725. : RUNREF  { selID ¥ svDP svBufPtr svState -- }
  1726.     DP -> svDP                ¥ save DP
  1727.     DP hiDP umax -> hiDP    ¥ so we can reset DP to right place on an error
  1728.  
  1729.     bufPtr NIF  runRefBuf  ELSE  bufPtr  THEN
  1730.     dup -> DP  -> svBufPtr    ¥ now we'll compile in runRefBuf
  1731.     state -> svState        ¥ save state
  1732.     postpone ]            ¥ need compile state so this compilation works properly
  1733.     selID compRef        ¥ compile the binding
  1734.     postpone (exit)        ¥ and an exit, so we return to interpretation
  1735.     svState -> state    ¥ restore state
  1736.     0 -> hiDP            ¥ don't need it any more and could cause problems
  1737.     ?unholdMod
  1738.     DP -> bufPtr        ¥ new bufPtr value
  1739.     svDP -> DP            ¥ restore DP since the code might compile something
  1740.     patches_done        ¥ we're about to execute what we just compiled
  1741.     svBufPtr execute    ¥ execute at old bufPtr location
  1742.     svBufPtr -> bufPtr    ¥ then restore old bufPtr
  1743. ;
  1744.  
  1745.  
  1746. ¥                ======== Selector support =========
  1747.  
  1748.  
  1749. ¥ MESSAGE is the handling word invoked by using a selector.
  1750.  
  1751. : MESSAGE        immediate
  1752.     state
  1753.     IF                      ¥ Compile state
  1754.         compRef                ¥ Compile the message send
  1755.         ?unHoldMod
  1756.     ELSE
  1757.         runRef                ¥ Run state - execute object/vector reference.
  1758.                             ¥ ?unHoldMod is called by ex-method at the
  1759.                             ¥ end, so we don't need to call it here.
  1760.     THEN  ;
  1761.  
  1762.  
  1763. ¥ 1stFind lumps together all the special cases we have to look for after
  1764. ¥ we've parsed an input word, but before we can do a regular dictionary
  1765. ¥ lookup.  At present these are selectors, named parms/locals, ivars
  1766. ¥ and local objects.  If we invent more later, they can easily be added.
  1767. ¥ The vector Ufind is then set to this word so it is called before the
  1768. ¥ regular dictionary search.  If we succeed here, we return the selector
  1769. ¥ ID or zero, the cfa of the handling word, and 1 or -1 (this will cause
  1770. ¥ FIND to exit without doing anything more).  If we fail, we return the
  1771. ¥ original string address and false.
  1772.  
  1773. : 1stFIND    ¥ ( str-addr -- selID message-cfa T  |  -- str-addr F )
  1774.     sel?                        ¥ is it a selector?
  1775.     IF        hash                ¥ yes - leave selID
  1776.             ['] message  1        ¥  and cfa of message, and 1 (it's immediate)
  1777.     ELSE    LocFind                ¥ no - look for the various kinds of local name
  1778.     THEN  ;
  1779.  
  1780.  
  1781. ' 1stFind -> Ufind
  1782.  
  1783. getSelect classinit:  -> initID
  1784.  
  1785.  
  1786. forward DUMP
  1787.  
  1788.  
  1789. ¥ SET_CLASS is a utility word used to patch nucleus objects when their classes
  1790. ¥ are defined in higher-level files.  Actually it could be used to change the
  1791. ¥ class of any object, if anyone is silly enough to want to do that.
  1792.  
  1793. ¥ Usage:  fFcb  ['] file  set_class
  1794.  
  1795. : SET_CLASS  { ^obj theClass -- }
  1796.     theClass  chkClass  ^obj 6 -  reloc!        ¥ Patch ^class
  1797.     6  ^obj 8 -  w!                    ¥ Not indexed (yet)
  1798.     -6 ^obj  2-  w!  ;                ¥ ^class offset
  1799.  
  1800.  
  1801. : CHKSAME        ¥ ( ^obj -- ^obj )
  1802.         ¥ A check that two objects are of exactly the
  1803.         ¥ same class.
  1804.     dup >classXt  ^base >classXt  <> ?error 87  ;
  1805.  
  1806.  
  1807. ¥            ========= Object pointers ==========
  1808.  
  1809. ¥ Object pointers are low-level objects (like VALUEs) which point to a
  1810. ¥ normal (high-level) object, and which allow early-bound messages to be
  1811. ¥ sent to the object by syntactically sending them to the object pointer.
  1812.  
  1813. ¥ The normal syntax is
  1814.  
  1815. ¥  ObjPtr  ZZZ    class_is  someClass
  1816.  
  1817. ¥ Thereafter, any messages sent to zzz are early-bound to the object that
  1818. ¥ zzz points to at the time the message executes.
  1819.  
  1820. ¥ If you need to declare the object pointer before the class exists, use
  1821. ¥ SET_TO_CLASS once the class is defined, thus:
  1822. ¥
  1823. ¥ :class  SOMECLASS    super{ object }
  1824. ¥
  1825. ¥    ' someOP  set_to_class  someClass
  1826. ¥
  1827. ¥    etc.
  1828.  
  1829.  
  1830. true    value    check_OP_stores?    ¥ allows us to turn off type checking
  1831.                                     ¥  for stores to objPtrs
  1832.  
  1833. : (ToOP)  { ^obj OPcfa ¥ OPcl -- }
  1834.  
  1835.     ^obj  nilP =                ¥ If we're storing nil, anything goes
  1836.     check_OP_stores? not or        ¥ Or if checking is turned off
  1837.     NIF
  1838.         OPcfa 4+ @abs  -> OPcl
  1839.         ^obj 6 - @abs  OPcl  <>
  1840.         IF                      ¥ Mismatch. We give some useful(?) info.
  1841.             cr  ^obj obj> .id ."  -> "  OPcfa .id
  1842.             87 die
  1843.         THEN
  1844.     THEN
  1845.     ^obj OPcfa !  ;
  1846.  
  1847.  
  1848. :f  ToObjPtr
  1849.     state
  1850.     IF  lit-addr  postpone (toOP)  ELSE  (toOP)  THEN  ;f
  1851.  
  1852.  
  1853. : CLASS_IS    ¥ ( --< class > )
  1854.     ?exec  '  chkClass  here 4-  reloc!  ;
  1855.  
  1856.  
  1857. : SET_TO_CLASS  { ^objPtr ¥ ^cl --< class > }
  1858.     '  -> ^cl
  1859.     ^objPtr hdlr -62 <> ?error 85        ¥ "That isn't an ObjPtr"
  1860.  
  1861.             ¥ Now if "class" is an imported word, we change the handler code
  1862.             ¥ to "imported class".  This is normally done when the module
  1863.             ¥ is compiled, but it may not be yet, since we probably
  1864.             ¥ want to refer to the ObjPtr in the module.
  1865.  
  1866.     ^cl hdlr -92 = IF  -90 ^cl 2- w!  ELSE  ^cl chkClass drop  THEN
  1867.     ^cl  ^objPtr 4+  reloc!  ;
  1868.  
  1869.  
  1870. ¥ If you are late-binding in a loop, it can be much faster if you do the bind
  1871. ¥ just once, then reuse the resulting cfa each time in the loop.  This way
  1872. ¥ you only have to perform the method search once.  To bind initially and get
  1873. ¥ the cfa, use
  1874.  
  1875. ¥  BIND_WITH ( ^obj --<selector> ^obj-modified  cfa )
  1876.  
  1877. ¥ Usage:  (saveCfa and ^obj-mod are values or locals)
  1878.  
  1879. ¥    (get object's address)  bind_with someSelector:  -> saveCfa  -> ^obj-mod
  1880.  
  1881. ¥    (in the loop)  ^obj-mod  saveCfa  ex-method
  1882.  
  1883. ¥ The use of the modified object address is a bit obscure, and is related to
  1884. ¥ multiple inheritance.  The method you actually end up binding to may be in
  1885. ¥ one of the superclasses, and the ivars for that superclass may not start at
  1886. ¥ the beginning of the object.  The modified object address is the start of
  1887. ¥ the ivars for the superclass, which is the address the method needs.
  1888.  
  1889. ¥ Note also that the method may turn out to be in a module, so when you have
  1890. ¥ finished you should put ?unHoldMod to free up the module.
  1891.  
  1892. : (BWITH)  { ^obj selID ¥ cfa offs -- ^obj-modified  cfa }
  1893.     selID ^obj ?>class  clFindm
  1894.     drop ( %%%% )
  1895.     -> offs  -> cfa
  1896.     ^obj offs +  cfa  ;
  1897.  
  1898.  
  1899. : BIND_WITH        ¥ ( ^obj --<selector> ^obj-modified  cfa )
  1900.     getSelect  postpone literal
  1901.     postpone (bwith)  ;        immediate
  1902.  
  1903.  
  1904. ¥        ===================================
  1905.  
  1906. :class    OBJECT    super{ meta }
  1907.  
  1908. :m CLASS:    ^base ?>class ?>classinMod  ;m
  1909.  
  1910. :m .ID:        ^base obj>  .id  ;m
  1911.  
  1912. :m .CLASS:    ^base >classXt  .id  ;m
  1913.  
  1914. :m ADDR:    inline{ ^base}  ;m
  1915. ¥        ^base  ;m
  1916.  
  1917. :m ABS:        ^base  ;m        ¥ Included for Neon/Yerk compatibility
  1918.  
  1919. :m LENGTH:    ¥ ( -- len )  Gets total length of object.
  1920.     objlen  ;m
  1921.  
  1922.  
  1923. (*    Here are two methods which operate between this object and another of
  1924.     the same class.  Note we don't check that the passed-in object is actually
  1925.     of the same class, since it could be a subclass but still be safe to use
  1926.     here.
  1927. *)
  1928.  
  1929. :m COPYTO:    ¥ ( ^obj -- )  Copies the ivar part of the passed-in object
  1930.             ¥ to self.
  1931.     ^base  dup (^dlen) w@  aligned_move  ;m
  1932.  
  1933. :m =?:        ¥ ( ^obj -- b )  Returns true if the ivar part of the passed-in
  1934.             ¥ object is identical to self.
  1935.     ^base  dup (^dlen) w@  (s=)  ;m
  1936.  
  1937. (*    The following methods need to be defined for all objects.
  1938.     We give them their default definitions here.
  1939. *)
  1940.  
  1941. :m CLASSINIT:  ;m    ¥ Our standard constructor method.  Called automatically
  1942.                     ¥ whenever an object is created.
  1943.  
  1944.  
  1945. :m DEEP_CLASSINIT:    ¥ Also does classinit: on all nested ivars.  Use for
  1946.                     ¥  totally (re-)initializing an object.
  1947.     ^base -> newObject
  1948.     class: self ifa displace  0  0
  1949.     ivSetup
  1950. ¥    classinit: [self]
  1951.     ?unholdMod  ;m
  1952.  
  1953.  
  1954. (*    RELEASE: is our standard destructor method.  Any objects that
  1955.     allocate heap storage will redefine this appropriately.
  1956.     Our convention is that an object will release ALL its
  1957.     storage when it gets a release: message. Other methods
  1958.     can be provided to partly release storage, as needed.
  1959. *)
  1960.  
  1961. :m RELEASE:    inline{ }  ;m
  1962.  
  1963.  
  1964. :m DUMP:
  1965.     .id: self  ."  class: "  .class: self
  1966.     ^base  objlen  dump  ;m
  1967.  
  1968. :m PRINT:        ¥ Used for a formatted display, if appropriate.
  1969.                 ¥ Default is just a dump.
  1970.     dump: self  ;m
  1971.  
  1972. ;class
  1973.  
  1974.  
  1975. ¥ Bytes is used as the allocation primitive for basic classes
  1976.  
  1977. : BYTES  { numBytes ¥ svRec? -- }
  1978.     ?class
  1979.     rec? -> svRec?  true -> rec?    ¥ Don't want an object header here
  1980.     ['] object ivDef
  1981.     numBytes  ^comp_class dfa  w+!
  1982.     svRec? -> rec?  ;
  1983.  
  1984.  
  1985.  
  1986. (*        ================  Temp (local) objects  ===================
  1987.  
  1988.     Syntax:
  1989.     
  1990.     : aWord  { loc1 loc2 -- }        ¥ Locals are optional, of course
  1991.         temp
  1992.         {    var        v1
  1993.             int        i1
  1994.             string    s
  1995.         }
  1996.  
  1997.     Or you can use temp{ ...  } if you prefer.
  1998.  
  1999.     As the syntax is quite similar to a list of ivars of a class, we actually
  2000.     implement the temp objects as though they're the ivars of a dummy class
  2001.     (which we uncreatively call Dummy).  This is just a convenience during
  2002.     the compilation of a defn with temp objects.  It allows us to define them
  2003.     and keep them visible during the compilation of the definition, while 
  2004.     being able to mainly use existing code for ivar access.  We don't need 
  2005.     these ivar dic entries once the defn is finished, so we actually put them
  2006.     high in the dictionary out of the way of the defn we're compiling.  At 
  2007.     the end of the defn, we reinitialize Dummy's ivar link ready for next time.
  2008. *)
  2009.  
  2010. getSelect release:        constant    releaseID
  2011.  
  2012.  
  2013. :class DUMMY  super{ object }
  2014. ;class
  2015.  
  2016. ' dummy ifa @    constant    dummyIfa
  2017.             ¥ ivar link corresponding to no ivars - it will be a relative
  2018.             ¥  pointer to the n-way for the superclass, and thus a constant
  2019.  
  2020. : RESETTEMPS
  2021.     dummyIfa  ['] dummy ifa  !
  2022.     0  ['] dummy dfa !                ¥ clear dlen and xwid
  2023. ;
  2024.     
  2025.     ¥ Note we don't have to worry about the mfa since Dummy never gets
  2026.     ¥ its own methods.
  2027.  
  2028.  
  2029. (*    InitTemps is called when we're compiling the prolog for a definition
  2030.     with temp objects.  It compiles a call to make_obj for each object, so
  2031.     that they're properly initialized.  Note we can't just call make_obj once
  2032.     using class Dummy, since its ivar list is wiped out after each defn
  2033.     with temp objects, so at run time it won't have any!  But we don't need
  2034.     Dummy at run time anyway - we only need the "ivars" which are the
  2035.     temp objects themselves.
  2036. *)
  2037.  
  2038. : 1TEMP  ( ^iclass ioffs -- )
  2039.     locReg +  make_obj  ;
  2040.     
  2041.  
  2042. :f INITTEMPS  { ¥ infa ^class -- }
  2043.     ['] dummy ifa displace  -> infa
  2044.     BEGIN
  2045.         infa @ 0<
  2046.     WHILE
  2047.         infa ^iclass -> ^class
  2048.         ^class xwid
  2049.         IF        ¥ it's indexed - we'll have #elements on the stack,
  2050.                 ¥  so we need to compile it as a literal for
  2051.                 ¥  make_obj to grab at run time.
  2052.             infa i#els  postpone literal
  2053.         THEN
  2054.         ^class lit-addr
  2055.         infa ioffs  postpone literal
  2056.         postpone locreg  postpone +  postpone make_obj
  2057.         infa ^nextivar  -> infa
  2058.     REPEAT  ;f
  2059.  
  2060.  
  2061. (*    ReleaseTemps is called back from Handlers when it's compiling an exit.
  2062.     It compiles a release: xxx for all temp objects.  Because of the way
  2063.     we've defined release: in class Object, for simple objects no code will
  2064.     actually be generated.  
  2065.     
  2066.     Note we mustn't call resetTemps here since this might be an EXIT, not
  2067.     the final semicolon.  We leave calling resetTemps till a new temp{ comes
  2068.     up.
  2069. *)
  2070.  
  2071. : RELEASETEMPS  { ¥ infa -- }
  2072.     ['] dummy ifa displace  -> infa
  2073.     BEGIN
  2074.         infa @ 0<
  2075.     WHILE
  2076.         infa  ^iclass  0EXIT            ¥ shouldn't happen, actually
  2077.         releaseID  infa  ivFindM 2drop
  2078.         infa ioffs bind_to_tmpObj        ¥ compile release:
  2079.         infa ^nextivar  -> infa
  2080.     REPEAT
  2081. ;
  2082.  
  2083.  
  2084. : }TEMP
  2085.     130 ?pairs
  2086.     ['] } >body !                        ¥ restore old action for "}"
  2087.     -> ^comp_class  -> state  -> cstate  -> DP    ¥ restore other things
  2088.     tmpObjs dlen 8 +  -> frameSize        ¥ work out frame size
  2089.     local? NIF                            ¥ compile prolog unless we're in
  2090.         PLentry  initTemps                ¥  a local section (then it gets done
  2091.     THEN                                ¥  by :LOC)
  2092.     ['] releaseTemps -> relTmps            ¥ for Handlers callback at exit time
  2093. ;
  2094.  
  2095.  
  2096. : TEMP{        immediate
  2097.  
  2098. (*    First we have to allocate an internal local variable as a frame pointer.
  2099.     There are 4 situations.  There may or may not already be locals, and
  2100.     we may or may not be in a local section.  Note we can be in a local
  2101.     section even if there aren't already locals, since the purpose of the
  2102.     local section might be just to establish a section for these temp objects.
  2103.  
  2104.     If there are already locals, we just add another.  If we're not in a
  2105.     local section we need to recompile the entry sequence (done by PLentry)
  2106.     since the number of regs to be saved and set up is different.  But if
  2107.     we're in a local section, we don't have to recompile since we haven't
  2108.     called PLentry yet, so we just add the extra local.  If there aren't any
  2109.     locals already, we just call initLocs which sets them up, before adding
  2110.     the new one.
  2111. *)
  2112.     resetTemps
  2113.     #PL IF
  2114.         local?    NIF  PLentry_addr -> DP  THEN
  2115.     ELSE
  2116.         initLocs                ¥ No locs before, so set up for them now
  2117.     THEN
  2118.     local? IF  -1 -> local?  THEN    ¥ If in a local section, setting local?
  2119.                                     ¥ to -1 means we've defined the locals
  2120.                                     ¥ so can't do it again
  2121.     " x " here place  here addToParmList
  2122.  
  2123. (*    next we save DP and move halfway up in the free dic space - we'll put
  2124.     the "ivar dic entries" for the temp objs there - we don't need them
  2125.     after the defn is compiled.
  2126. *)
  2127.     here            room 2/ ++> DP  align-dp
  2128.     cstate            true -> cstate
  2129.     state
  2130.     ^comp_class
  2131.     ['] } >body @                ¥ save old action for "}"
  2132.     ['] }temp  -> }                ¥ "}" will now be same as }temp
  2133.     130                            ¥ for ?pairs
  2134.  
  2135.     ['] dummy dup    -> ^comp_class    ¥ local objs will look like ivars of Dummy
  2136.                     -> tmpObjs        ¥ this will enable finding them
  2137.     
  2138.  
  2139.  
  2140.     postpone [                    ¥ stop compiling
  2141. ;
  2142.  
  2143.                             
  2144. : TEMP        gobble{  postpone temp{  ;        immediate
  2145.  
  2146.  
  2147. (*        =================  Records and unions  ====================
  2148.  
  2149. Syntax:
  2150.  
  2151.     record <name>        ¥ The name is optional
  2152.    {    var        v1
  2153.         int        i1
  2154.         string    s
  2155.    }
  2156.    
  2157.        union <name>        ¥ The name is optional
  2158.    {    var        v1
  2159.         int        i1
  2160.         string    s
  2161.    }
  2162.  
  2163.  
  2164. Or you can use record{ ...  } or union{ ... } if you prefer, if it's
  2165. unnamed.  The similarity of syntax to temp objects is quite deliberate.
  2166. But any similarity to Your Favorite Language is entirely accidental.  Well
  2167. actually it's not, but I think this syntax is as good as any, and probably
  2168. more readable for folks coming from the land of C.
  2169.  
  2170. unions can be nested within records and vice versa.
  2171.  
  2172. NOTE: it's best to not use unions unless you're really sure you know what
  2173. you're doing.  Having different objects sharing the same memory is sure
  2174. to cause problems if you're careless!
  2175.  
  2176. *)
  2177.  
  2178. : SVREC        
  2179.    ^comp_class dfa w@ 
  2180.     rec?  
  2181.     union?  
  2182.     unionOffs 
  2183. ;
  2184.  
  2185. : RSTREC    
  2186.     -> unionOffs  
  2187.     -> union?  
  2188.     -> rec?  
  2189.     union? IF     ¥ we fell back in a union, so we
  2190.                 ¥ reset data pointer to were it was at the beginning
  2191.                 ¥ of this union/rec
  2192.         ^comp_class dfa w!
  2193.     ELSE
  2194.         drop
  2195.     THEN
  2196. ;
  2197.  
  2198. : ?HANDLE_NAME  { ¥ sv_>in sv_^class sv_rec? -- }
  2199.     >in @ -> sv_>in ^comp_class -> sv_^class  rec? -> sv_rec?
  2200.     Mword  count  " {" s=
  2201.     NIF                            ¥ we've got a name for the record
  2202.         true -> rec?            ¥ must do this before defining the name "object"
  2203.         sv_>in  >in !
  2204.         ['] object  ivDef
  2205.         sv_rec? -> rec?  sv_^class -> ^comp_class
  2206.         gobble{                    ¥ "{" must follow
  2207.     THEN
  2208. ;
  2209.  
  2210.  
  2211. : }RECORD
  2212.     131 ?pairs  rstRec
  2213.     ['] } >body !  ;
  2214.  
  2215.  
  2216. : RECORD{
  2217.     ?class                        ¥ must be compiling a class
  2218.     ['] } >body @                    ¥ save old action for "}"
  2219.     ['] }record  -> }            ¥ "}" will now be same as }record
  2220.     svRec                        ¥ save parameters for any existing record/union
  2221.     131                            ¥ for ?pairs
  2222.     true -> rec?  false -> union?  ;
  2223.  
  2224. : RECORD
  2225.     ?handle_name
  2226.     record{  ;
  2227.  
  2228. : 68k_record{    record{  ;        ¥ we need to distinguish on the PowerPC
  2229. : 68k_record    record   ;
  2230.  
  2231.  
  2232. : }UNION
  2233.     132 ?pairs
  2234.     unionOffs  ^comp_class dfa w!    
  2235.     rstRec
  2236.     ['] } >body !  ;                ¥ restore old action for "}"
  2237.  
  2238. : UNION{
  2239.     ?class                        ¥ must be compiling a class
  2240.     ['] } >body @                    ¥ save old action for "}"
  2241.     ['] }union  -> }            ¥ "}" will now be same as }union
  2242.     svRec                        ¥ save record/union parameters
  2243.     132                            ¥ for ?pairs
  2244.     true -> rec?  true -> union?
  2245.     ^comp_class dfa w@ -> unionOffs  ;
  2246.  
  2247.  
  2248. : UNION
  2249.     ?handle_name
  2250.     union{  ;
  2251.  
  2252.  
  2253. (*        =================  Static ivars ====================
  2254.  
  2255. Syntax:
  2256.  
  2257.     static
  2258.    {    var        v1
  2259.         int        i1
  2260.         string    s
  2261.    }
  2262.  
  2263. Or you can use  static{ ...  } if you prefer.
  2264.  
  2265. These are like static class variables in C++ - they belong to the class,
  2266. not the object, and thus are shared by all objects of the class.  We
  2267. allocate each ivar in the dictionary right after its ivar header.
  2268. *)
  2269.  
  2270. : }STATIC
  2271.     133 ?pairs
  2272.     ['] } >body !                    ¥ restore old action for "}"
  2273.     false -> static?  ;
  2274.  
  2275.  
  2276. : STATIC{
  2277.     ?class                        ¥ must be compiling a class
  2278.     ['] } >body @                ¥ save old action for "}"
  2279.     ['] }static  -> }            ¥ "}" will now be same as }static
  2280.     133                            ¥ for ?pairs
  2281.     true -> static?  ;
  2282.  
  2283. : STATIC
  2284.     gobble{  static{  ;
  2285.  
  2286.  
  2287. ¥            ==========================================
  2288.  
  2289. ¥ CL1 is our first cleanup word - called on an abort.  Resets things
  2290. ¥  to normal.  Later cleanup words do their special stuff, then call CL1.
  2291.  
  2292. : CL1
  2293.     (;cl)  clrComp  ['] (}) -> }
  2294.     resetTemps  false -> rec?  false -> union?
  2295.     false -> compinline?
  2296.     0 -> extraFind
  2297.     0 -> bufPtr
  2298.     DP hiDP umax  -> DP
  2299.     false -> case_in_names?
  2300. ;
  2301.  
  2302. ' cl1  -> abortVec
  2303.  
  2304.  
  2305. load Struct
  2306.  
  2307. ¥            ==========================================
  2308.  
  2309. (* Normally we don't get here.  In order to do various tests on classes,
  2310.  we comment out the  <" Struct  and run these torture tests:
  2311. *)
  2312.  
  2313. : ?CHK    <> abort" check FAILED!!!"  ;    ¥ error if something doesn't
  2314.                                         ¥  give what we expect
  2315.  
  2316.  
  2317. :class    VAR    super{ object }
  2318.  
  2319.     4 bytes data
  2320.  
  2321. :m CLEAR:
  2322.     inline{ 0 ^base !}  ;m
  2323. ¥    0 ^base !  ;m
  2324.  
  2325. :m GET:
  2326.     inline{ ^base @}  ;m
  2327. ¥    ^base @  ;m
  2328.  
  2329. :m PUT:
  2330.     inline{ ^base !}  ;m
  2331. ¥    ^base !  ;m
  2332.  
  2333. :m GETT:    ^base @  ;m
  2334.     
  2335. :m PUTT:    ^base !  ;m
  2336.  
  2337. :m +:
  2338.     inline{ ^base +!}  ;m
  2339. ¥    ^base +!  ;m
  2340. :m -:
  2341.     inline{ ^base -!}  ;m
  2342. ¥    ^base -!  ;m
  2343. :m ->:
  2344.     inline{ @ ^base !}  ;m
  2345. ¥    chksame  get: var  put: self  ;m
  2346.  
  2347. :m TEST:        db  ;m
  2348.  
  2349. mlocal LOCTEST:  { aa ¥ bb cc -- }
  2350.  
  2351. :m AAA:    aa -> bb ;m
  2352.  
  2353. :mloc  LOCTEST:
  2354.     aaa: self  cc -> bb  1234 drop ;mloc
  2355.  
  2356.  
  2357. :m PRINT:
  2358.     ^base @  .  ;m
  2359.  
  2360. :m CLASSINIT:    $ 123  put: self  ;m
  2361.  
  2362. ;class
  2363.  
  2364.  
  2365. :class    BYTE    super(  object  )
  2366.  
  2367.     1 bytes data
  2368.  
  2369. :m CLEAR:
  2370.     inline{ 0 obj c!}
  2371.     0 ^base c!  ;m
  2372.  
  2373. :m GET:
  2374.     inline{ obj c@x}
  2375.     ^base c@x  ;m
  2376.  
  2377. :m UGET:
  2378.     inline{ obj c@}
  2379.     ^base c@  ;m
  2380.  
  2381. :m PUT:
  2382.     inline{ obj c!}
  2383.     ^base c!  ;m
  2384.  
  2385. :m ->:
  2386.     inline{ c@ obj c!}
  2387.     chksame  c@  put: self  ;m
  2388.  
  2389. :m PRINT:
  2390.     ^base c@  .        ;m
  2391.  
  2392. :m CLASSINIT:    9 put: self  ;m
  2393.  
  2394. ;class
  2395.  
  2396. ¥ some very simple testing, to start with:
  2397.  
  2398. var        aVar
  2399. byte    aByte
  2400.  
  2401. 987 avar !
  2402. get: avar    987 ?chk
  2403. : q  get: avar  ;
  2404. q            987 ?chk
  2405.  
  2406.  
  2407. :class    BOOL    super(  byte  )
  2408.  
  2409. :m GET:
  2410.     inline{ obj c@x}
  2411.     ^base c@x  ;m
  2412.  
  2413. :m PUT:
  2414.     inline{ 0<> obj c!}
  2415.     0<>  ^base c!  ;m
  2416.  
  2417. :m SET:
  2418.     inline{ true obj c!}
  2419.     true ^base c!  ;m
  2420.  
  2421. :m PRINT:
  2422.     get: self  IF  ." true"  ELSE  ." false"  THEN  ;m
  2423.  
  2424. :m CLASSINIT:    clear: self  ;m
  2425.  
  2426. ;class
  2427.  
  2428.  
  2429. :class    BARRAY  super{ object }  1 indexed
  2430.  
  2431. :m  AT:        ¥ ( index -- n )
  2432.     inline{ ix c@}
  2433.     ^elem1  c@  ;m
  2434.  
  2435. :m  TO:        ¥ ( n index -- )
  2436.     inline{ ix c!}
  2437.     ^elem1  c!  ;m
  2438.  
  2439.  
  2440. :m ^ELEM:    ¥ ( index -- addr )
  2441.     inline{ ix}
  2442.     ^elem1  ;m
  2443.  
  2444. :m FILL:    ¥ ( value -- )  Fills all elements with value.
  2445.     idxbase  limit 2*  bounds
  2446.     ?DO  dup  i c!  LOOP  drop  ;m
  2447.  
  2448. :m WIDTH:    1  ;m        ¥ Faster than the default in Object
  2449.  
  2450. :m GETELEM:    ¥ ( addr -- n )  Fetches one element at addr
  2451.     c@x  ;m
  2452.  
  2453. ;class
  2454.  
  2455.  
  2456. +echo
  2457.  
  2458. ¥ bug test here:
  2459.  
  2460. :class    INDEXED-OBJ  super{ object }
  2461.  
  2462. :m ^ELEM:    ^elem  ;m
  2463.  
  2464. :m LIMIT:    limit  ;m
  2465.  
  2466. :m WIDTH:    idxbase  6 -  w@  ;m
  2467.  
  2468. :m IXADDR:    idxbase  ;m
  2469.  
  2470. :m CLEARX:    ¥ Erases indexed area.
  2471.     idxbase  limit  width: self  *  erase  ;m
  2472.  
  2473. :m CLASSINIT:    clearX: self  ;m
  2474.  
  2475. ;class
  2476.  
  2477.  
  2478. :class    WARRAY  super{ indexed-obj }  2 indexed
  2479.  
  2480. :m AT:        ¥ ( index -- n )
  2481.     inline{ ^elem w@x}  ;m
  2482.  
  2483. :m TO:        ¥ ( n index -- )
  2484.     inline{ ^elem w!}  ;m
  2485.  
  2486. ;class
  2487.  
  2488.  
  2489. :class  TRIGTABLE    super{ wArray }
  2490.  
  2491.     3    wArray  AXISVALS
  2492. ;class
  2493.  
  2494. 10 trigtable ttt
  2495.  
  2496. : q  9 at: ttt  ;
  2497.  
  2498.  
  2499. ¥ Testing static and public ivars
  2500.  
  2501.  
  2502. :class SIVTEST  super{ var }
  2503. public
  2504. static
  2505. {    var        V1
  2506.     bool    B1
  2507.     byte    B2
  2508. 10    barray    BB
  2509. }
  2510.     bool    BLOC
  2511.     var        VLOC
  2512.     
  2513. :m QQ:    get: v1  get: b1  get: b2 4 at: bb
  2514.         get: vloc  ;m
  2515.  
  2516. :m CLASSINIT:
  2517.         32 put: v1  set: b1  33 put: b2  34 4 to: bb
  2518.         set: bloc  34 put: vloc  ;m
  2519. ;class
  2520.  
  2521. sivtest zzz
  2522. sivtest sss
  2523. objPtr myop  class_is sivtest
  2524.  
  2525. : QQQ        addr: ivar> v1 in_class sivtest  drop
  2526.             get: ivar> b2 in_class sivtest
  2527.             get: ivar> v1 in_class sivtest
  2528.             sss get: ivar> bloc in class_as> sivtest  ;
  2529.  
  2530. qqq
  2531. -1    ?chk
  2532. 32    ?chk
  2533. 33    ?chk
  2534.  
  2535.  
  2536. :class HAHA  super{ object }
  2537.  
  2538.     sivtest    IVsss
  2539.     
  2540. :m QQ:      get: ivar> vloc IN ivsss  ;m
  2541. ;class
  2542.  
  2543. haha hh
  2544.  
  2545. qq: hh
  2546. 34 ?chk
  2547.  
  2548. : WWW  temp { sivtest mysiv }
  2549.     get: ivar> vloc IN mysiv
  2550.     mysiv -> myop
  2551.     get: ivar> vloc IN myop  ;
  2552.     
  2553. www
  2554. 34 ?chk
  2555. 34 ?chk
  2556.  
  2557.     get: ivar> vloc IN zzz
  2558. 34 ?chk
  2559.  
  2560.  
  2561. ¥ Testing record{
  2562.  
  2563. :class VAR+ super{ var }
  2564.  
  2565. :m QQ:    get: [self]        ¥ should make class general
  2566.         get: [ self ]    ¥ shouldn't give any error
  2567. ;m
  2568.  
  2569. ;class
  2570.  
  2571. var+ VVV
  2572. qq: vvv        ¥ no need for ?chk since it will give its own error
  2573.  
  2574.  
  2575. :class RECTEST super{ object }
  2576.     var    vv
  2577.     record RR
  2578.     {        var        v1
  2579.             bool    b1
  2580.         3    barray  bbb
  2581.             byte    dummyToMakeAddrOdd
  2582.         union {    byte    b2
  2583.                 var        v2
  2584.                 record    {    byte bb1
  2585.                             byte bb2    }
  2586.             }
  2587.             var        v3
  2588.     }
  2589.     
  2590. :m TEST:
  2591.     get: v1  put: b1  get: b2  get: v2  get: bb1  get: bb2  get: v3
  2592. ;m
  2593. ;class
  2594.  
  2595. recTest rrr
  2596. test: rrr
  2597. $ 123        ?chk
  2598. 0            ?chk
  2599. 9            ?chk
  2600. $ 09000123    ?chk
  2601. 9            ?chk
  2602. $ 123        ?chk
  2603. $ 123        ?chk
  2604.  
  2605. rrr $ 24 + @  $ 09000123  ?chk
  2606.  
  2607. ¥ Testing temp objects
  2608.  
  2609. : q
  2610. temp
  2611. {    var    v1
  2612.      var    v2
  2613. }temp
  2614.     v1 v2
  2615.     get: v1  get: v2  ;
  2616.  
  2617. q
  2618. $ 123    ?chk
  2619. $ 123    ?chk
  2620. 2drop
  2621.  
  2622. :class INT  super( object )
  2623.  
  2624.     2    bytes    data
  2625.  
  2626. :m CLEAR:
  2627.     inline{  0 obj !  }
  2628.     0 ^base !  ;m
  2629.  
  2630. :m UGET:
  2631.     inline{  ^base w@  }
  2632.     ^base w@  ;m
  2633.  
  2634. :m GET:
  2635.     inline{  obj w@x  }
  2636.     ^base w@x  ;m
  2637.  
  2638. :m IPUT:    ^base w!  ;m
  2639.  
  2640. :m DISP:
  2641.     inline{  obj 2+ @  }  ;m
  2642.  
  2643. :m PUT:
  2644.     inline{  obj w!  }
  2645.     ^base  w!  ;m
  2646.  
  2647. :m MOVE:
  2648.     inline{  obj 4+ w@  obj w!  }  ;m
  2649.  
  2650.  
  2651. :m +:    inline{  obj w+!  }
  2652.     ^base  w+!  ;m
  2653.  
  2654. :m ->:
  2655.     inline{  w@ obj w!  }
  2656.     chksame  1234 drop  get: int  put: self  ;m
  2657.  
  2658. :m ++>:
  2659.     inline{  w@ obj w+!  }
  2660.     chksame  uget: int  +: self  ;m
  2661.  
  2662. :m .ID:    ." haha"  ;m
  2663.  
  2664. :m TEST:
  2665.     1234 drop  .id: super  ;m
  2666.  
  2667. :m CLASSINIT:    $ 456 put: self  ;m
  2668.  
  2669. ;class
  2670.  
  2671.  
  2672. :class CC  super{ byte int var bool }
  2673.  
  2674. :m TEST:
  2675.     uget: self        ¥ offs should be 0
  2676.     +: self                ¥ offs should be 4
  2677.     set: self  ;m        ¥ offs should be A
  2678.  
  2679. :m TEST1:
  2680.     set: self
  2681.     get: super> bool    ¥ should get -1
  2682.     get: super
  2683. ;m
  2684.     
  2685. :m classinit:  ( db )  ;m
  2686.  
  2687. ;class
  2688.  
  2689. cc CCC
  2690.  
  2691. ccc @        $ 0900fff6    ?chk
  2692. ccc 4+ @    $ 0456fff2    ?chk
  2693. ccc 8 + @    $ 123        ?chk
  2694.  
  2695.  
  2696. :class STRANGE  super{ object }
  2697.     var VV
  2698.     byte BB
  2699. :m GET:  get: vv  get: bb  ;m
  2700. :m PUT:  put: bb  put: vv  ;m
  2701.  
  2702. ;class
  2703.  
  2704.  
  2705. :class    ARRAY    super(  object  )    4 indexed
  2706.  
  2707. ¥ 8 bytes data        ¥ Comment out to check collapsing of embedded objs
  2708.  
  2709. :m ^ELEM:    ¥ ( index -- addr )
  2710.     ^elem4  ;m
  2711.  
  2712. :m QQQ:    inline{ ix }  ;m
  2713.  
  2714. :m  AT:        ¥ ( index -- n )
  2715.     inline{ ix @ }
  2716.     ^elem4  @  ;m
  2717.  
  2718. :m  ATT:    ^elem  @  ;m        ¥ As for AT:, but not inline
  2719.                 ¥  and uses unoptimized ^elem
  2720.  
  2721. :m  TO:        ¥ ( n index -- )
  2722.     inline{  ix !  }
  2723.     ^elem4  !  ;m
  2724.  
  2725. :m  +TO:        ¥ ( n index -- )
  2726.     inline{ ix +! }
  2727.     ^elem4  +!  ;m
  2728.  
  2729. :m -TO:        ¥ ( n index -- )
  2730.     inline{ ix -! }
  2731.     ^elem4  -!  ;m
  2732.  
  2733. :m FILL:        ¥ ( value -- )  Fills all elements with value.
  2734.     idxbase  limit 4*  bounds
  2735.     DO  dup  i !  4 +LOOP  drop  ;m
  2736.  
  2737. :m EXEC:        ¥ ( index -- )  execute the cfa, by jumping there.
  2738.     inline{ ix ex}
  2739.     ^elem: self  execute  ;m
  2740.  
  2741. :m TEST:
  2742.     exec: self  ;m
  2743.  
  2744. :m ATEST:
  2745.     1 at: self  ;m
  2746.  
  2747. ;class
  2748.  
  2749.  
  2750. :class MULT    super( var int array )
  2751.  
  2752. :m MTEST:    uget: super  999 1 to: self  ;m
  2753. :m MAT:        at: self  ;m
  2754. ;class
  2755.  
  2756.  
  2757. objPtr    OO    class_is mult
  2758. objPtr    OOO    class_is int
  2759.  
  2760. :class IVXX    super( object )
  2761.     10 bytes data2
  2762.     int    i1
  2763.     int    i2
  2764.     130 bytes qqqq        ¥ Include to check >128 distance
  2765.                         ¥  index addressing of array qwert
  2766.     9 array qwert
  2767.  
  2768. :m ITEST:
  2769.     get: i1  uget: i2  66 put: i2
  2770.     99 3 to: qwert  1234 drop  3 at: qwert
  2771.     addr: i2  ['] ooo !  ;m
  2772.  
  2773. :m GETQWERT:
  2774.     addr: qwert  ;m
  2775. ;class
  2776.  
  2777. int ii
  2778. 3 mult    mm
  2779. ivxx    iv
  2780.  
  2781. mm -> oo
  2782.  
  2783. itest: iv
  2784.  
  2785. $ 63    ?chk
  2786. $ 456    ?chk
  2787. $ 456    ?chk
  2788.  
  2789. mtest: mm
  2790. $ 456    ?chk
  2791.  
  2792. 88 iput: mm        ¥ Note: get: mm will bind to the var, but uget: mm
  2793.                 ¥ will bind to the int and give 88.
  2794.  
  2795. get: mm  $ 123    ?chk
  2796. uget: mm 88        ?chk
  2797.  
  2798.  
  2799. ¥ A further test - Doug H found this bug:
  2800.  
  2801. :class  POINT    super{ object }
  2802.     int    Y        ¥ Vertical coordinate
  2803.     int    X        ¥ Horizontal  coordinate
  2804. ;class
  2805.  
  2806.  
  2807. :class  RECT  super{ object }
  2808.     point    TOPL
  2809.     point    BOTR
  2810. ;class
  2811.  
  2812. :class test1 super{ object }
  2813.  
  2814.     20 array a
  2815.  
  2816. :m classinit:
  2817.     55 0 to: a ;m
  2818.  
  2819. :m to:  to: a ;m
  2820.  
  2821. :m at:  at: a ;m
  2822.  
  2823. ;class
  2824.  
  2825. :class test3 super{ rect test1 }
  2826. :m classinit:
  2827.     [ 1 -> supers_to_skip ]  classinit: super
  2828. ;m
  2829. ;class
  2830.  
  2831. test3 t3
  2832.  
  2833. : q            getqwert: iv  3 swap at: **  ;    ¥ Should give 99
  2834. : qq        1 at: mm ;                        ¥ Should give 999
  2835. : qqq        1 mat: mm  ;                    ¥ Should give 999
  2836. : qqqq        1 mm at: mult  ;                ¥ Should give 999
  2837. : z            1 mm at: **  ;                    ¥ Should give 999
  2838. : zz        1 mm at: array ;                ¥ Should fail
  2839. : y            1 at: oo   ;                    ¥ Should give 999
  2840. : yy        1 mat: oo  ;                    ¥ Should give 999
  2841. : yyy        uget: mm  ;                        ¥ Should optimize & give 88
  2842. : yyyy        addr: mm  addr: oo  ;            ¥ Both numbers shd be same
  2843. : yyyyy        uget: ooo  ;                    ¥ Should give 66
  2844. : yyyyyy    0 at: t3  ;                        ¥ Should give 55
  2845.  
  2846.  
  2847. q         99    ?chk
  2848. qq         999    ?chk
  2849. qqq     999    ?chk
  2850. qqqq     999 ?chk
  2851. z         999    ?chk
  2852. y         999    ?chk
  2853. yy         999    ?chk
  2854. yyy     88    ?chk
  2855. yyyy        ?chk
  2856. yyyyy     66    ?chk
  2857. yyyyyy    55    ?chk
  2858.  
  2859. ¥ torture tests WORKED!  INCREDIBLE!!  CONGRATULATIONS!!!
  2860. ¥ (but remember to check that ZZ gives a "can't use indexed method" error)
  2861. key!
  2862.